From a5f07dae01c635b97630b8dc9f65241a6b0b87d7 Mon Sep 17 00:00:00 2001 From: jmbaud Date: Sun, 14 Jul 2024 17:16:33 +0200 Subject: [PATCH 1/3] Solves #8 issue. --- src/gctl.c | 641 +++++++--- src/gctl.h | 120 +- src/main.c | 239 ++-- src/menu.c | 61 +- src/menu.h | 6 + src/optionio.c | 497 +++++++- src/sar.h | 68 +- src/sarmenubuild.c | 866 ++++++++++--- src/sarmenucb.c | 38 +- src/sarmenucodes.h | 47 +- src/sarmenumanage.c | 569 +++++++-- src/sarmenuoptions.c | 2794 ++++++++++++++++++++++++++++++------------ src/sarmenuoptions.h | 5 + 13 files changed, 4524 insertions(+), 1427 deletions(-) diff --git a/src/gctl.c b/src/gctl.c index cd6e0b5..1a074e8 100644 --- a/src/gctl.c +++ b/src/gctl.c @@ -26,6 +26,9 @@ static char *last_gctl_error = NULL; char *GCtlGetError(void); +void GctlJsOpenAndMapp(gctl_struct *gc, gctl_values_struct *v); +int GetSdlJsIndexFromGuidString(char *guid); +int GetSdlJsIndexFromGcSdlJoystick(gctl_struct *gc, int i); gctl_struct *GCtlNew(gctl_values_struct *v); void GCtlUpdate( gctl_struct *gc, @@ -79,181 +82,356 @@ char *GCtlGetError(void) return(last_gctl_error); } + /* - * Initializes the Game Controller with the specified values. + * (Re)open game controller joysticks and open/map SDL joysticks to + * relevant game controller joystick. + * + * * If not yet done: + * - Allocates gc->joystick structure + * - Initializes SDL library joystick subsystem + * - Allocates gc->sdljoystick structure + * + * * Depending of calling function: + * - if 'v' pointer is not null, initializes the Game Controller with + * the specified 'v' values. + * - if 'v' pointer is null, open all plugged sdl joysticks which are + * mapped to at least one role. + * + * * Always: + * - Mapps SDL joysticks to the right gc->joysticks. This is necessary + * for joystick hot plug because SDL_Joystick device_index changes + * each time that a joystick is unplugged / replugged. + * - Open all (up to MAX_JOYSTICKS) plugged SDL joysticks which are not + * yet been mapped or opened. + * */ -gctl_struct *GCtlNew(gctl_values_struct *v) +void GctlJsOpenAndMapp(gctl_struct *gc, gctl_values_struct *v) { - int i; - - gctl_js_struct *joystick; +//fprintf(stderr, "%s:%d : Entering GctlJsOpenAndMapp()\n", __FILE__, __LINE__); gctl_values_js_struct *js_value; - gctl_struct *gc = GCTL(calloc(1, sizeof(gctl_struct))); - + gctl_js_struct *gc_joystick; + SDL_Joystick *sdljoystick; + int i, device_index; last_gctl_error = NULL; - if(gc == NULL) - { - last_gctl_error = "Memory allocation error"; - return(NULL); - } + /* As SDL_JoystickOpened() function as been removed from SDL library, + * add a bit array to store which sdl joysticks are already opened. + */ + Boolean sdl_joystick_opened[MAX_JOYSTICKS] = { False }; - /* Game Controller Values not specified? */ - if(v == NULL) - { - free(gc); - last_gctl_error = "Game Controller Values not specified"; - return(NULL); - } + if(gc == NULL) + return; - /* Set controller(s) and option(s) */ - gc->controllers = v->controllers; - gc->options = v->options; + /* If not yet done, allocate gc->joysticks structure */ - /* Initialize the joystick? */ - if(v->controllers & GCTL_CONTROLLER_JOYSTICK) + if(gc->joystick == NULL) { - gctl_js_axis_roles axis_role; - - /* Allocate Game Controller Joysticks */ - gc->total_joysticks = v->total_joysticks; - gc->joystick = GCTL_JS(calloc( - gc->total_joysticks, sizeof(gctl_js_struct) - )); + gc->total_joysticks = MAX_JOYSTICKS; + gc->joystick = GCTL_JS(calloc(gc->total_joysticks, sizeof(gctl_js_struct))); if(gc->joystick == NULL) { + fprintf(stderr, "%s:%d: Can't allocate gc->joystick\n", __FILE__, __LINE__); gc->total_joysticks = 0; + return; } + else + { + /* Clear gc joysticks mappings */ - SDL_SetHint(SDL_HINT_JOYSTICK_ALLOW_BACKGROUND_EVENTS, "1"); - /* Attempt to initialize the joystick subsystem. */ - if (SDL_Init(SDL_INIT_JOYSTICK) != 0) { - fprintf(stderr, "Unable to initialize SDL joysticks: %s\n", SDL_GetError()); - gc->sdljoystick = NULL; - gc->total_joysticks = 0; - } else if (gc->total_joysticks > 0){ - /* Allocate space for SDL_Joystick structure */ - gc->sdljoystick = calloc(gc->total_joysticks, sizeof(SDL_Joystick*)); + for(i = 0; i < gc->total_joysticks; i++) + { + gc_joystick = &gc->joystick[i]; + + strcpy(gc_joystick->sdl_guid_s, ""); + + gc_joystick->axes_inversion_bits = 0; + + gc_joystick->axis_heading = -1; + gc_joystick->axis_pitch = -1; + gc_joystick->axis_bank = -1; + gc_joystick->axis_throttle = -1; + gc_joystick->pov_hat = -1; + gc_joystick->axis_hat_x = -1; + gc_joystick->axis_hat_y = -1; + gc_joystick->axis_brake_left = -1; + gc_joystick->axis_brake_right = -1; + + gc_joystick->button_rotate = -1; + gc_joystick->button_air_brakes = -1; + gc_joystick->button_wheel_brakes = -1; + gc_joystick->button_zoom_in = -1; + gc_joystick->button_zoom_out = -1; + gc_joystick->button_hoist_up = -1; + gc_joystick->button_hoist_down = -1; + } } + } + /* If not yet done, initialize SDL library joystick and events subsystems */ - /* Iterate through each joystick */ - for(i = 0; i < gc->total_joysticks; i++) + if(!SDL_WasInit(SDL_INIT_JOYSTICK)) + { + /* Attempt to initialize SDL joystick and events subsystems. */ + if(SDL_Init(SDL_INIT_JOYSTICK) == 0) { - /* Get pointer to current Game Controller Joystick and - * Joystick Values + /* SDL is ready */ + + /* Because joystick events subsystem is automatically set by + * SDL_Init(SDL_INIT_JOYSTICK) call, from now SDL_PollEvent(...) + * can be called to read joystick events. + * Joystick events will be shutted off later when we will not need + * them anymore (i.e. at joystick test menu exit) by calling + * SDL_JoystickEventState() function. */ - joystick = &gc->joystick[i]; - js_value = &v->joystick[i]; - - - axis_role = js_value->axis_role; + } + else + { + sprintf(last_gctl_error, "Unable to initialize SDL joysticks: %s", SDL_GetError()); + gc->sdljoystick = NULL; + gc->total_joysticks = 0; + gc->total_sdl_joysticks = 0; + return; + } + } - /* Enable SDL joysticks */ - if (SDL_NumJoysticks() > i) - { - fprintf(stderr, "Found SDL Joystick #%d of %d\n", i, SDL_NumJoysticks()); - //SDL_JoystickEventState(SDL_ENABLE); - gc->sdljoystick[i] = SDL_JoystickOpen(i); - } + /* If not yet done, allocate gc->sdljoystick structure. + * + * Note: as size of SDL_Joystick* is very small (it's only a pointer), + * don't waste time to allocate / reallocate it depending of real number + * of plugged joysticks (i.e. SDL_NumJoysticks()). + */ + gc->total_sdl_joysticks = MAX_JOYSTICKS; - /* Begin setting up joystick axis mappings */ + if(gc->sdljoystick == NULL) + { + gc->sdljoystick = calloc(gc->total_sdl_joysticks, sizeof(SDL_Joystick*)); + if(gc->sdljoystick == NULL) + { + fprintf(stderr, "%s:%d: Can't allocate gc->sdljoystick\n", __FILE__, __LINE__); + gc->total_sdl_joysticks = 0; + return; + } + } - /* Reset all axis mappings first */ - joystick->axis_heading = -1; - joystick->axis_brake_left = -1; - joystick->axis_brake_right = -1; - joystick->axis_bank = -1; - joystick->axis_pitch = -1; - joystick->axis_throttle = -1; - joystick->axis_hat_x = -1; - joystick->axis_hat_y = -1; + /* Mapp each SDL joystick to the right gc->joystick (if any). This is + * necessary for joystick hot plug because a SDL joystick device_index + * can change each time this joystick is unplugged / replugged. + * + * For example if we connect a stick then a throttle, + * SDL joystick device index will be 0 for stick and 1 for throttle, + * but if we disconnect them then reconnect the throttle then the stick, + * SDL joystick device index will be 1 for stick and 0 for throttle. + */ + + /* Initialize the Game Controller with the specified values? */ + if( v != NULL) + { + /* Open all plugged sdl joysticks which are referenced by v */ - /* Throttle and rudder unit? */ - if(axis_role & GCTL_JS_AXIS_ROLE_AS_THROTTLE_AND_RUDDER) - { - joystick->axis_heading = 0; - joystick->axis_throttle = 1; - } - else if(axis_role & GCTL_JS_AXIS_ROLE_AS_RUDDER_AND_BRAKES) + for(i = 0; i < gc->total_joysticks; i++) + { + js_value = &v->joystick[i]; + /* Iterate through all plugged sdl joysticks */ + for(device_index = 0; device_index < gc->total_sdl_joysticks; device_index++) { - int num_axes = SDL_JoystickNumAxes(gc->sdljoystick[i]); - switch (num_axes) { - case 1: - joystick->axis_heading = 0; - break; - case 2: - joystick->axis_brake_left = 0; - joystick->axis_brake_right = 0; - joystick->axis_heading = 1; + /* This v->joystick identical to current SDL joystick ? */ + if(GetSdlJsIndexFromGuidString(js_value->sdl_guid_s) == device_index) + { + sdljoystick = SDL_JoystickOpen(device_index); + if(sdljoystick != NULL){ + sdl_joystick_opened[device_index] = True; + gc->sdljoystick[i] = sdljoystick; + + fprintf(stderr, + "Open SDL joystick index #%d as: Joystick #%d, %s, vendorID = 0x%04x, productID = 0x%04x\n", + device_index, + i + 1, + SDL_JoystickName(sdljoystick), + SDL_JoystickGetVendor(sdljoystick), + SDL_JoystickGetProduct(sdljoystick) + ); break; - case 3: - joystick->axis_brake_left = 0; - joystick->axis_brake_right = 1; - joystick->axis_heading = 2; + } + else + { + fprintf(stderr, "Can't open SDL joystick #%d (of %d)\n", + device_index, SDL_NumJoysticks() + ); + + gc->sdljoystick[i] = NULL; break; + } } } - /* Joystick with no axises (only buttons) */ - else if(axis_role & GCTL_JS_AXIS_ROLE_NONE) - { + } + return; + } + else + { + /* Open all plugged sdl joysticks which are already mapped. */ - } - /* Joystick as a standard composite unit */ - else + for(i = 0; i < gc->total_joysticks; i++) + { + gc_joystick = &gc->joystick[i]; + + /* Iterate through plugged sdl joysticks */ + for(device_index = 0; device_index < gc->total_sdl_joysticks; device_index++) { - /* Get bank axis */ - if(axis_role & GCTL_JS_AXIS_ROLE_BANK) - joystick->axis_bank = 0; - /* Get heading axis */ - if(axis_role & GCTL_JS_AXIS_ROLE_HEADING) - joystick->axis_heading = 2; - /* Get pitch axis */ - if(axis_role & GCTL_JS_AXIS_ROLE_PITCH) - joystick->axis_pitch = 1; - - /* Get throttle axis */ - if(axis_role & GCTL_JS_AXIS_ROLE_THROTTLE) + /* This sdl joystick same as this gc joystick? */ + if(GetSdlJsIndexFromGuidString(gc_joystick->sdl_guid_s) == device_index) { - /* Check if heading axis is valid, if not then - * throttle is axis 2 - */ - if(joystick->axis_heading < 0) - joystick->axis_throttle = 2; - else - joystick->axis_throttle = 3; + sdljoystick = SDL_JoystickOpen(device_index); + if(sdljoystick != NULL) + { + sdl_joystick_opened[device_index] = True; + gc->sdljoystick[i] = sdljoystick; + break; + } } + } + } + } + + /* If there is enough free gc joysticks left, open all plugged sdl + * joysticks which have not yet been mapped or opened. + */ + + for(i = 0; i < gc->total_joysticks; i++) + { + gc_joystick = &gc->joystick[i]; - /* Get hat x and y axis */ - if(axis_role & GCTL_JS_AXIS_ROLE_HAT) + /* This gc joystick not yet mapped? */ + if(strlen(gc_joystick->sdl_guid_s) == 0) + { + for(device_index = 0; device_index < gc->total_sdl_joysticks; device_index++) + { + if(sdl_joystick_opened[device_index] == False) { - /* Hat x */ - if(joystick->axis_heading < 0) - { - if(joystick->axis_throttle < 0) - joystick->axis_hat_x = 2; - else - joystick->axis_hat_x = 3; - } - else if(joystick->axis_throttle < 0) - { - joystick->axis_hat_x = 3; - } - else + sdljoystick = SDL_JoystickOpen(device_index); + if(sdljoystick != NULL) { - joystick->axis_hat_x = 4; + sdl_joystick_opened[device_index] = True; + gc->sdljoystick[i] = sdljoystick; + break; } - /* Hat y (the axis after hat x) */ - joystick->axis_hat_y = - joystick->axis_hat_x + 1; } - } /* Joystick as a standard composite unit */ + } + } + } +//fprintf(stderr, "%s:%d : Exiting GctlJsOpenAndMapp()\n", __FILE__, __LINE__); +} + +/* + * Returns the sdl joystick device index wich corresponds + * to the given sdl joystick guid string. + * Returns -1 if no corespondence found. + */ +int GetSdlJsIndexFromGuidString(char *guid) +{ + SDL_JoystickGUID sdl_guid; + char sdl_js_guid_s[33]; + int i, device_index = -1; + + if(strlen(guid) == 0) + return device_index; + for(i = 0; i < SDL_NumJoysticks(); i++){ + sdl_guid = SDL_JoystickGetDeviceGUID(i); + SDL_JoystickGetGUIDString(sdl_guid, sdl_js_guid_s, + sizeof(sdl_js_guid_s)); + + if(!strcmp(guid, sdl_js_guid_s)){ + device_index = i; + break; + } + } + + return device_index; +} + +/* + * Returns the sdl joystick device index wich corresponds + * to the given gc->sdljoystick. + * Returns -1 if no corespondence found. + */ +int GetSdlJsIndexFromGcSdlJoystick(gctl_struct *gc, int i) +{ + int j, device_index = -1; + + if(gc != NULL && gc->sdljoystick[i] != NULL) + { + for(j = 0; j < gc->total_sdl_joysticks; j++) + { + if(gc->sdljoystick[i] == SDL_JoystickOpen(j)){ + device_index = j; + break; + } + } + } + + return device_index; +} + +/* + * Initializes the Game Controller with the specified values. + */ +gctl_struct *GCtlNew(gctl_values_struct *v) +{ +//fprintf(stderr, "%s:%d : Entering GCtlNew()\n", __FILE__, __LINE__); + int i; + gctl_js_struct *joystick; + gctl_values_js_struct *js_value; + gctl_struct *gc = GCTL(calloc(1, sizeof(gctl_struct))); + + last_gctl_error = NULL; + + /* Game Controller Values not specified? */ + if(v == NULL) + { + free(gc); + last_gctl_error = "Game Controller Values not specified"; + return(NULL); + } + + /* Set controller(s) and option(s) */ + gc->controllers = v->controllers; + gc->options = v->options; + + /* Initialize joystick? */ + if(v->controllers & GCTL_CONTROLLER_JOYSTICK) + { + /* Open SDL joysticks and map them to relevant gc joysticks */ + GctlJsOpenAndMapp(gc, v); + + /* Iterate through each joystick */ + for(i = 0; i < gc->total_joysticks; i++) + { + /* Get pointer to current Game Controller Joystick and + * Joystick Values + */ + joystick = &gc->joystick[i]; + js_value = &v->joystick[i]; + + /* Begin setting up joystick mappings */ + /* Copy joystick mappings from js_value structure */ + + strcpy(joystick->sdl_guid_s, js_value->sdl_guid_s); + + joystick->axes_inversion_bits = js_value->js_axes_inversion_bits; + + joystick->axis_heading = js_value->axis_heading; + joystick->axis_pitch = js_value->axis_pitch; + joystick->axis_bank = js_value->axis_bank; + joystick->axis_throttle = js_value->axis_throttle; + joystick->pov_hat = js_value->pov_hat; + joystick->axis_hat_x = js_value->axis_hat_x; + joystick->axis_hat_y = js_value->axis_hat_y; + joystick->axis_brake_left = js_value->axis_brake_left; + joystick->axis_brake_right = js_value->axis_brake_right; - /* Begin setting up joystick button mappings */ - /* Copy joystick button mappings from js_value structure */ joystick->button_rotate = js_value->button_rotate; joystick->button_air_brakes = js_value->button_air_brakes; joystick->button_wheel_brakes = js_value->button_wheel_brakes; @@ -261,10 +439,8 @@ gctl_struct *GCtlNew(gctl_values_struct *v) joystick->button_zoom_out = js_value->button_zoom_out; joystick->button_hoist_up = js_value->button_hoist_up; joystick->button_hoist_down = js_value->button_hoist_down; - - - } /* Iterate through each joystick */ - } /* Initialize joystick? */ + } /* Iterate through each joystick */ + } /* Initialize joystick? */ /* Initialize keyboard? */ @@ -306,8 +482,7 @@ gctl_struct *GCtlNew(gctl_values_struct *v) gc->pointer_x = (gc->pointer_box_width / 2); gc->pointer_y = (gc->pointer_box_height / 2); } /* Initialize pointer? */ - - +//fprintf(stderr, "%s:%d : Exiting GCtlNew()\n", __FILE__, __LINE__); return(gc); } @@ -370,6 +545,9 @@ void GCtlUpdate( for(i = 0; i < gc->total_joysticks; i++) { joystick = &gc->joystick[i]; + if(joystick == NULL) + continue; + sdljoystick = gc->sdljoystick[i]; /* Update defined joystick operations for this joystick. * This is to tabulate a list of functions that were @@ -416,12 +594,12 @@ void GCtlUpdate( axis_bank = joystick->axis_bank, axis_pitch = joystick->axis_pitch, axis_throttle = joystick->axis_throttle, + pov_hat = joystick->pov_hat, axis_hat_x = joystick->axis_hat_x, axis_hat_y = joystick->axis_hat_y, axis_brake_left = joystick->axis_brake_left, - axis_brake_right = joystick->axis_brake_right; - - + axis_brake_right = joystick->axis_brake_right, + axes_inversion_bits = joystick->axes_inversion_bits; /* Check bank to heading modifier */ if((joystick->button_rotate > -1) && @@ -438,22 +616,39 @@ void GCtlUpdate( /* Heading */ if((axis_heading > -1) && - !gc->axis_kb_state) + !gc->axis_kb_state){ gc->heading = ((float)SDL_JoystickGetAxis(sdljoystick, axis_heading) / 32768.0); + if(axes_inversion_bits & GCTL_JS_AXIS_INV_HEADING) + gc->heading = -gc->heading; + } + + /* Bank */ if((axis_bank > -1) && - !gc->axis_kb_state) + !gc->axis_kb_state){ gc->bank = ((float)SDL_JoystickGetAxis(sdljoystick, axis_bank) / 32768.0); + if(axes_inversion_bits & GCTL_JS_AXIS_INV_BANK) + gc->bank = -gc->bank; + } + /* Pitch */ if((axis_pitch > -1) && - !gc->axis_kb_state) + !gc->axis_kb_state){ gc->pitch = - ((float)SDL_JoystickGetAxis(sdljoystick, axis_pitch) / 32768.0); + if(axes_inversion_bits & GCTL_JS_AXIS_INV_PITCH) + gc->pitch = -gc->pitch; + } + + /* Throttle */ if((axis_throttle > -1) && - !gc->axis_kb_state) + !gc->axis_kb_state){ gc->throttle = 1.0 - (((float)SDL_JoystickGetAxis(sdljoystick, axis_throttle) + 32768.0) / 65536.0); + if(axes_inversion_bits & GCTL_JS_AXIS_INV_THROTTLE) + gc->throttle = -gc->throttle + 1.0; + } /* Wheel brakes: we do not make a distinction between left and right and handle both */ float brake_coeff_left = 0; @@ -461,33 +656,54 @@ void GCtlUpdate( if((axis_brake_left > -1) && !gc->axis_kb_state) { int axis_brake_left_val = SDL_JoystickGetAxis(sdljoystick, axis_brake_left); - brake_coeff_left = ((float)axis_brake_left_val + 32768.0) / 65536.0; + brake_coeff_left = 1.0 - ((float)axis_brake_left_val + 32768.0) / 65536.0; + + if(axes_inversion_bits & GCTL_JS_AXIS_INV_BRAKE_LEFT) + brake_coeff_left = -brake_coeff_left; } if((axis_brake_right > -1) && !gc->axis_kb_state) { int axis_brake_right_val = SDL_JoystickGetAxis(sdljoystick, axis_brake_right); - brake_coeff_right = ((float)axis_brake_right_val + 32768.0) / 65536.0; + brake_coeff_right = 1.0 - ((float)axis_brake_right_val + 32768.0) / 65536.0; + + if(axes_inversion_bits & GCTL_JS_AXIS_INV_BRAKE_RIGHT) + brake_coeff_right = -brake_coeff_right; } - float brake_coeff = MAX(brake_coeff_left, brake_coeff_right); if (axis_brake_left > -1 || axis_brake_right > -1) { - if(brake_coeff > 0) - { - gc->wheel_brakes_state = 1; - gc->wheel_brakes_coeff = brake_coeff; - } else { - gc->wheel_brakes_state = 0; - gc->wheel_brakes_coeff = 0; + float brake_coeff = roundf(MAX(brake_coeff_left, brake_coeff_right) * 100) / 100; + + switch(gc->wheel_brakes_state){ + case 0: + case 1: + if(brake_coeff > 0) + { + gc->wheel_brakes_state = 1; + gc->wheel_brakes_coeff = brake_coeff; + } else { + gc->wheel_brakes_state = 0; + gc->wheel_brakes_coeff = 0; + } + + if(brake_coeff >= 1.0 && gc->shift_state) + gc->wheel_brakes_state = 2; + break; + case 2: + if(!gc->shift_state && brake_coeff >= 0.01) + gc->wheel_brakes_state = 1; + break; } } - /* Hat */ - if ((axis_hat_x > -1) && (axis_hat_y > -1)) + /* Point Of View */ + + /* POV as a standard hat (switches) */ + if (pov_hat > -1) { - int pos = SDL_JoystickGetHat(sdljoystick,0); + int pos = SDL_JoystickGetHat(sdljoystick, pov_hat); switch (pos) { case SDL_HAT_CENTERED: gc->hat_y= 0.0f; @@ -530,6 +746,29 @@ void GCtlUpdate( gc->hat_x= 0.0f; break; } + if(axes_inversion_bits & GCTL_JS_AXIS_INV_POV_HAT){ + gc->hat_x = -gc->hat_x; + gc->hat_y = -gc->hat_y; + } + } + /* POV as 2 analog axes */ + else if ((axis_hat_x > -1) && (axis_hat_y > -1)) + { + gc->hat_x = (float)SDL_JoystickGetAxis(sdljoystick, axis_hat_x) / 32768.0; + gc->hat_y = - ((float)SDL_JoystickGetAxis(sdljoystick, axis_hat_y) / 32768.0); + + /* Add a +/-1% dead band to avoid POV drift */ + if(gc->hat_x < 0.01f && gc->hat_x > -0.01f) + gc->hat_x = 0.0f; + if(gc->hat_y < 0.01f && gc->hat_y > -0.01f) + gc->hat_y = 0.0f; + + if(axes_inversion_bits & GCTL_JS_AXIS_INV_HAT_X){ + gc->hat_x = -gc->hat_x; + } + if(axes_inversion_bits & GCTL_JS_AXIS_INV_HAT_Y){ + gc->hat_y = -gc->hat_y; + } } @@ -578,40 +817,75 @@ void GCtlUpdate( gc->ctrl_state = (SDL_JoystickGetButton(sdljoystick, joystick->button_rotate)) ? True : False; /* Air brakes */ - if (joystick->button_air_brakes > -1 && !gc->button_kb_state){ + if (joystick->button_air_brakes > -1 && !gc->button_kb_state) + { + /* As air brakes are toggled on/off, do a rising edge detection + * to avoid state jiggling. + */ + + /* Joystick button pressed? */ if ( SDL_JoystickGetButton( sdljoystick, - joystick->button_air_brakes)){ - gc->air_brakes_state = gc->air_brakes_state ? False : True; - gc->air_brakes_coeff = gc->air_brakes_state ? 1.0f : 0.0f; + joystick->button_air_brakes) + ) + { + /* Joystick button was previously released? */ + if(gc->air_brakes_js_btn_released){ + + /* Button is pressed and was previously released, + * we can toggle state. + */ + + gc->air_brakes_state = gc->air_brakes_state ? False : True; + gc->air_brakes_coeff = gc->air_brakes_state ? 1.0f : 0.0f; + + /* Joystick button is now pressed */ + gc->air_brakes_js_btn_released = False; + } } + /* Joystick button not pressed */ + else + gc->air_brakes_js_btn_released = True; } - /* Wheel brakes - only if not controlled by axis and enabled already*/ - if (joystick->button_wheel_brakes > -1 && !gc->button_kb_state && !gc->wheel_brakes_state) + + /* Wheel brakes - only if not controlled by axis and enabled already */ + if (joystick->button_wheel_brakes > -1 && !gc->button_kb_state) { - gc->wheel_brakes_state = SDL_JoystickGetButton( + int wheel_brake_btn_pressed = SDL_JoystickGetButton( sdljoystick, joystick->button_wheel_brakes) ? True : False; gc->wheel_brakes_coeff = gc->wheel_brakes_state ? 1.0f : 0.0f; - if (gc->wheel_brakes_state) - { - if (gc->shift_state) - gc->wheel_brakes_state = 2; - else - gc->wheel_brakes_state = 1; - } - else - { - if (gc->wheel_brakes_state != 2) - gc->wheel_brakes_state = 0; + /* Wheel brakes states: + * 0 : wheel brakes OFF + * 1 : wheel brakes ON + * 2 : parking brake ON + * + * Push button to apply wheel brakes, release button to + * release wheel brakes. + * Push button and press key then release button + * before release key to activate parking brake. + * When in parking brake state, push button to release brakes. + */ + switch(gc->wheel_brakes_state){ + case 0: + if (wheel_brake_btn_pressed && !gc->shift_state) + gc->wheel_brakes_state = 1; + else if (wheel_brake_btn_pressed && gc->shift_state) + gc->wheel_brakes_state = 2; + break; + case 1: + if (!wheel_brake_btn_pressed && !gc->shift_state) + gc->wheel_brakes_state = 0; + else if (wheel_brake_btn_pressed && gc->shift_state) + gc->wheel_brakes_state = 2; + break; + case 2: + if (wheel_brake_btn_pressed && !gc->shift_state) + gc->wheel_brakes_state = 0; + break; } } - - - - - } /* Iterate through each joystick */ } /* Check if joystick updating is needed and allowed */ @@ -1036,7 +1310,7 @@ void GCtlHandleKey( btn_kb_coeff = &gc->wheel_brakes_coeff; btn_kb_last = &gc->wheel_brakes_kb_last; DO_BTN_KB_UPDATE - gc->wheel_brakes_state = (int)*btn_kb_state; + gc->wheel_brakes_state = (int)*btn_kb_state; } gc->button_kb_state = state; break; @@ -1152,5 +1426,4 @@ void GCtlDelete(gctl_struct *gc) } free(gc); - SDL_Quit(); } diff --git a/src/gctl.h b/src/gctl.h index 2c8b15b..8bf69ff 100644 --- a/src/gctl.h +++ b/src/gctl.h @@ -47,21 +47,19 @@ typedef enum { /* - * Joystick Axis Roles: + * Joystick Axis Inversion Bits: */ typedef enum { - GCTL_JS_AXIS_ROLE_PITCH = (1 << 0), - GCTL_JS_AXIS_ROLE_BANK = (1 << 1), - GCTL_JS_AXIS_ROLE_HEADING = (1 << 2), - GCTL_JS_AXIS_ROLE_THROTTLE = (1 << 3), - GCTL_JS_AXIS_ROLE_HAT = (1 << 4), - /* Throttle and rudder unit joystick */ - GCTL_JS_AXIS_ROLE_AS_THROTTLE_AND_RUDDER = (1 << 6), - /* Joystick unit with no axises (only buttons) */ - GCTL_JS_AXIS_ROLE_NONE = (1 << 7), - /* Triggers brakes */ - GCTL_JS_AXIS_ROLE_AS_RUDDER_AND_BRAKES = (1 << 8) -} gctl_js_axis_roles; + GCTL_JS_AXIS_INV_HEADING = (1 << 0), + GCTL_JS_AXIS_INV_PITCH = (1 << 1), + GCTL_JS_AXIS_INV_BANK = (1 << 2), + GCTL_JS_AXIS_INV_THROTTLE = (1 << 3), + GCTL_JS_AXIS_INV_HAT_X = (1 << 4), + GCTL_JS_AXIS_INV_HAT_Y = (1 << 5), + GCTL_JS_AXIS_INV_POV_HAT = (1 << 6), + GCTL_JS_AXIS_INV_BRAKE_LEFT = (1 << 7), + GCTL_JS_AXIS_INV_BRAKE_RIGHT = (1 << 8) +} gctl_js_axes_inversion_bits; /* @@ -81,13 +79,37 @@ typedef struct { /* Pointer to the toplevel window handle (for Win32) */ void *window; - /* Axis role flags (any of GCTL_JS_AXIS_ROLE_*), this basically - * specifies how many axises there are and each of their roles + /* SDL_GUID, in ASCII string representation. + * If this string is filled, it means that joystick is mapped + * to at least one role. */ - gctl_js_axis_roles axis_role; + char sdl_guid_s[32+1]; + /* Joystick name. + * Name is only given to help player for joystick configuration, + * no treatment is made on it. + */ + char *sdl_js_name; + + /* Axes inversion bits. Bit 0 for axis role 0, and so on... + * Each corresponding bit is set if axis movement must be inverted. + */ + gctl_js_axes_inversion_bits js_axes_inversion_bits; + + /* Joystick axes mappings, indicates which joystick axis + * number corresponds with which role + */ + int axis_heading, + axis_pitch, + axis_bank, + axis_throttle, + axis_hat_x, + axis_hat_y, + pov_hat, + axis_brake_left, + axis_brake_right; /* Joystick button mappings, indicates which joystick button - * number corresponds with which action + * number corresponds with which role */ int button_rotate, /* Button that treats * bank as heading axis @@ -129,11 +151,19 @@ typedef struct { * Used in gctl_struct */ typedef struct { + /* SDL_GUID, in ASCII string representation. + * If this string is filled, it means that joystick is mapped + * to at least one role. + */ + char sdl_guid_s[32+1]; + /* Joystick name. + * Name is only given to help player for joystick configuration, + * no treatment is made on it. + */ + char *sdl_js_name; - /* Axis role mappings, reffers an axis by number to a specific - * role - * - * The axis number can be -1 for non-existant + /* Joystick axis role mappings, reffers an axis by number to + * a specific role (-1 for none) */ int axis_heading, axis_bank, @@ -141,9 +171,15 @@ typedef struct { axis_throttle, axis_hat_x, axis_hat_y, + pov_hat, axis_brake_left, axis_brake_right; + /* Axes inversion bits. Bit 0 for axis role 0, and so on... + * Each corresponding bit is set if axis movement must be inverted. + */ + int axes_inversion_bits; + /* Joystick button role mappings, reffers a button by number to * a specific role (-1 for none) */ @@ -160,6 +196,20 @@ typedef struct { } gctl_js_struct; #define GCTL_JS(p) ((gctl_js_struct *)(p)) + +/* + * Used in gctl_struct. + * Only defined when mapping menu is activated and for each axis + * of each joystick (8 axes * 3 joysticks). + */ +typedef struct { + /* Joysticks axes min and max reached values. */ + Sint16 min, + max; +} gctl_js_mapping_menu_data_struct; +#define GCTL_JS_MAPPING_MENU_DATA(p) ((gctl_js_mapping_menu_data_struct *)(p)) + + /* * Game Controller: * @@ -231,12 +281,15 @@ typedef struct { * *_state members specifies a boolean on/off value * *_kb_last members record the last keyboard event for this * behavior + * * air_brakes_js_btn_released is used for joystick air brakes + * button rising edge detection. * *_coeff members determines the magnitude [0.0 to 1.0] of * the state regardless if it is on or off. This is for when * the game controller has gone from off to on to off in one * call to GCtlUpdate() */ - Boolean air_brakes_state; + Boolean air_brakes_state, + air_brakes_js_btn_released; int wheel_brakes_state; /* 0 = off * 1 = on * 2 = parking brakes @@ -302,17 +355,38 @@ typedef struct { /* Joystick specific stuff */ + /* Maximum number of joysticks and maximum number of analog axes, + * buttons and hats per joystick. + * These numbers cannot be modified without modifying a lot of code: + * opt->jsX, mapping menu spins, option spins call back, and so on... + * + * Three joysticks can hold: + * Flight stick + * Throttle controller + * Rudder controller + */ +#define MAX_JOYSTICKS 3 +#define MAX_JOYSTICK_AXES 8 +#define MAX_JOYSTICK_BTNS 16 +#define MAX_JOYSTICK_HATS 2 + /* Each structure reffers to a joystick */ gctl_js_struct *joystick; int total_joysticks; /* we add a an array for SDL joystick here. */ - SDL_Joystick **sdljoystick; + SDL_Joystick **sdljoystick; + int total_sdl_joysticks; + /* Used only in mapping menu for axes movement detection. */ + gctl_js_mapping_menu_data_struct *js_mapping_axes_values; } gctl_struct; #define GCTL(p) ((gctl_struct *)(p)) extern char *GCtlGetError(void); +extern void GctlJsOpenAndMapp(gctl_struct *gc, gctl_values_struct *v); +extern int GetSdlJsIndexFromGuidString(char *guid); +extern int GetSdlJsIndexFromGcSdlJoystick(gctl_struct *gc, int i); extern gctl_struct *GCtlNew(gctl_values_struct *v); extern void GCtlUpdate( gctl_struct *gc, diff --git a/src/main.c b/src/main.c index b90310d..9f1761d 100644 --- a/src/main.c +++ b/src/main.c @@ -63,6 +63,7 @@ #include "sarmenubuild.h" #include "sarmenumanage.h" #include "sarmenucodes.h" +#include "sarmenuoptions.h" #include "sarsimend.h" #include "config.h" @@ -187,10 +188,12 @@ void SARHandleSignal(int s) */ int SARInitGCTL(sar_core_struct *core_ptr) { - int i, total_joysticks; +//fprintf(stderr, "%s:%d : Entering SARInitGCTL()\n", __FILE__, __LINE__); + int i; void *w, *rc; gctl_struct *gctl; gctl_values_struct *v; + gctl_values_js_struct *js_v; gw_display_struct *display = core_ptr->display; const sar_option_struct *opt = &core_ptr->option; @@ -208,19 +211,6 @@ int SARInitGCTL(sar_core_struct *core_ptr) )) return(-1); - /* Check how many joysticks are specified by the options by - * checking if axis roles defined for each joystick in question - * - * Any joystick with one or more axis roles set means the stick - * is enabled - */ - total_joysticks = 0; - if(opt->gctl_js0_axis_roles != 0) - total_joysticks++; - if(opt->gctl_js1_axis_roles != 0) - total_joysticks++; - - /* Set up Game Controller Values */ v = GCTL_VALUES(calloc(1, sizeof(gctl_values_struct))); @@ -230,46 +220,98 @@ int SARInitGCTL(sar_core_struct *core_ptr) /* Options (none at this time) */ v->options = opt->gctl_options; - /* Set up Game Controller Joystick Values for each joystick - * that is enabled - */ - v->total_joysticks = total_joysticks; - if(total_joysticks > 0) - v->joystick = (gctl_values_js_struct *)calloc( - total_joysticks, sizeof(gctl_values_js_struct) - ); - else - v->joystick = NULL; + /* Set up Game Controller Joystick Values for each joystick */ + v->total_joysticks = MAX_JOYSTICKS; + v->joystick = (gctl_values_js_struct *)calloc( + MAX_JOYSTICKS, sizeof(gctl_values_js_struct) + ); + /* Joystick #1 */ i = 0; - if((total_joysticks > i) && (opt->gctl_js0_axis_roles != 0)) - { - gctl_values_js_struct *js_v = &v->joystick[i]; - js_v->window = w; - js_v->axis_role = opt->gctl_js0_axis_roles; - js_v->button_rotate = opt->js0_btn_rotate; - js_v->button_air_brakes = opt->js0_btn_air_brakes; - js_v->button_wheel_brakes = opt->js0_btn_wheel_brakes; - js_v->button_zoom_in = opt->js0_btn_zoom_in; - js_v->button_zoom_out = opt->js0_btn_zoom_out; - js_v->button_hoist_up = opt->js0_btn_hoist_up; - js_v->button_hoist_down = opt->js0_btn_hoist_down; - } + js_v = &v->joystick[i]; + + js_v->window = w; + + strcpy(js_v->sdl_guid_s, opt->js0_sdl_guid_s); + /* Do not copy opt->js0_sdl_name */ + + js_v->button_rotate = opt->js0_btn_rotate; + js_v->button_air_brakes = opt->js0_btn_air_brakes; + js_v->button_wheel_brakes = opt->js0_btn_wheel_brakes; + js_v->button_zoom_in = opt->js0_btn_zoom_in; + js_v->button_zoom_out = opt->js0_btn_zoom_out; + js_v->button_hoist_up = opt->js0_btn_hoist_up; + js_v->button_hoist_down = opt->js0_btn_hoist_down; + + js_v->axis_heading = opt->js0_axis_heading; + js_v->axis_bank = opt->js0_axis_bank; + js_v->axis_pitch = opt->js0_axis_pitch; + js_v->axis_throttle = opt->js0_axis_throttle; + js_v->axis_hat_x = opt->js0_axis_hat_x; + js_v->axis_hat_y = opt->js0_axis_hat_y; + js_v->pov_hat = opt->js0_pov_hat; + js_v->axis_brake_left = opt->js0_axis_brake_left; + js_v->axis_brake_right = opt->js0_axis_brake_right; + + js_v->js_axes_inversion_bits = opt->js_axes_inversion_bits; + /* Joystick #2 */ i = 1; - if((total_joysticks > i) && (opt->gctl_js1_axis_roles != 0)) - { - gctl_values_js_struct *js_v = &v->joystick[i]; - js_v->window = w; - js_v->axis_role = opt->gctl_js1_axis_roles; - js_v->button_rotate = opt->js1_btn_rotate; - js_v->button_air_brakes = opt->js1_btn_air_brakes; - js_v->button_wheel_brakes = opt->js1_btn_wheel_brakes; - js_v->button_zoom_in = opt->js1_btn_zoom_in; - js_v->button_zoom_out = opt->js1_btn_zoom_out; - js_v->button_hoist_up = opt->js1_btn_hoist_up; - js_v->button_hoist_down = opt->js1_btn_hoist_down; - } + js_v = &v->joystick[i]; + + js_v->window = w; + + strcpy(js_v->sdl_guid_s, opt->js1_sdl_guid_s); + /* Do not copy opt->js1_sdl_name */ + + js_v->button_rotate = opt->js1_btn_rotate; + js_v->button_air_brakes = opt->js1_btn_air_brakes; + js_v->button_wheel_brakes = opt->js1_btn_wheel_brakes; + js_v->button_zoom_in = opt->js1_btn_zoom_in; + js_v->button_zoom_out = opt->js1_btn_zoom_out; + js_v->button_hoist_up = opt->js1_btn_hoist_up; + js_v->button_hoist_down = opt->js1_btn_hoist_down; + + js_v->axis_heading = opt->js1_axis_heading; + js_v->axis_bank = opt->js1_axis_bank; + js_v->axis_pitch = opt->js1_axis_pitch; + js_v->axis_throttle = opt->js1_axis_throttle; + js_v->axis_hat_x = opt->js1_axis_hat_x; + js_v->axis_hat_y = opt->js1_axis_hat_y; + js_v->pov_hat = opt->js1_pov_hat; + js_v->axis_brake_left = opt->js1_axis_brake_left; + js_v->axis_brake_right = opt->js1_axis_brake_right; + + js_v->js_axes_inversion_bits = opt->js_axes_inversion_bits; + + /* Joystick #3 */ + i = 2; + js_v = &v->joystick[i]; + + js_v->window = w; + + strcpy(js_v->sdl_guid_s, opt->js2_sdl_guid_s); + /* Do not copy opt->js2_sdl_name */ + + js_v->button_rotate = opt->js2_btn_rotate; + js_v->button_air_brakes = opt->js2_btn_air_brakes; + js_v->button_wheel_brakes = opt->js2_btn_wheel_brakes; + js_v->button_zoom_in = opt->js2_btn_zoom_in; + js_v->button_zoom_out = opt->js2_btn_zoom_out; + js_v->button_hoist_up = opt->js2_btn_hoist_up; + js_v->button_hoist_down = opt->js2_btn_hoist_down; + + js_v->axis_heading = opt->js2_axis_heading; + js_v->axis_bank = opt->js2_axis_bank; + js_v->axis_pitch = opt->js2_axis_pitch; + js_v->axis_throttle = opt->js2_axis_throttle; + js_v->axis_hat_x = opt->js2_axis_hat_x; + js_v->axis_hat_y = opt->js2_axis_hat_y; + js_v->pov_hat = opt->js2_pov_hat; + js_v->axis_brake_left = opt->js2_axis_brake_left; + js_v->axis_brake_right = opt->js2_axis_brake_right; + + js_v->js_axes_inversion_bits = opt->js_axes_inversion_bits; /* Initialize the Game Controller */ @@ -278,6 +320,7 @@ int SARInitGCTL(sar_core_struct *core_ptr) free(v->joystick); free(v); +//fprintf(stderr, "%s:%d : Exiting SARInitGCTL()\n", __FILE__, __LINE__); /* Error initializing the Game Controller? */ if(gctl == NULL) @@ -1370,31 +1413,70 @@ sar_core_struct *SARInit(int argc, char **argv) GCTL_CONTROLLER_POINTER; opt->gctl_options = 0; - opt->js0_btn_rotate = 3; - opt->js0_btn_air_brakes = 6; - opt->js0_btn_wheel_brakes = 0; - opt->js0_btn_zoom_in = 2; - opt->js0_btn_zoom_out = 1; - opt->js0_btn_hoist_up = 5; - opt->js0_btn_hoist_down = 4; - - opt->js1_btn_rotate = 3; - opt->js1_btn_air_brakes = 6; - opt->js1_btn_wheel_brakes = 0; - opt->js1_btn_zoom_in = 2; - opt->js1_btn_zoom_out = 1; - opt->js1_btn_hoist_up = 5; - opt->js1_btn_hoist_down = 4; -/* - opt->gctl_js0_axis_roles = GCTL_JS_AXIS_ROLE_PITCH | - GCTL_JS_AXIS_ROLE_BANK; - */ - opt->gctl_js0_axis_roles = 0; - opt->gctl_js1_axis_roles = 0; -/* - opt->gctl_js1_axis_roles = -GCTL_JS_AXIS_ROLE_AS_THROTTLE_AND_RUDDER; - */ + /* No need to initialize + * opt->js0_sdl_name + */ + strcpy(opt->js0_sdl_guid_s, ""); + opt->js0_btn_rotate = -1; + opt->js0_btn_air_brakes = -1; + opt->js0_btn_wheel_brakes = -1; + opt->js0_btn_zoom_in = -1; + opt->js0_btn_zoom_out = -1; + opt->js0_btn_hoist_up = -1; + opt->js0_btn_hoist_down = -1; + opt->js0_axis_heading = -1; + opt->js0_axis_pitch = -1; + opt->js0_axis_bank = -1; + opt->js0_axis_throttle = -1; + opt->js0_axis_hat_x = -1; + opt->js0_axis_hat_y = -1; + opt->js0_pov_hat = 0; + opt->js0_axis_brake_left = -1; + opt->js0_axis_brake_right = -1; + + /* No need to initialize + * opt->js1_sdl_name + */ + strcpy(opt->js1_sdl_guid_s, ""); + opt->js1_btn_rotate = -1; + opt->js1_btn_air_brakes = -1; + opt->js1_btn_wheel_brakes = -1; + opt->js1_btn_zoom_in = -1; + opt->js1_btn_zoom_out = -1; + opt->js1_btn_hoist_up = -1; + opt->js1_btn_hoist_down = -1; + opt->js1_axis_heading = -1; + opt->js1_axis_pitch = -1; + opt->js1_axis_bank = -1; + opt->js1_axis_throttle = -1; + opt->js1_axis_hat_x = -1; + opt->js1_axis_hat_y = -1; + opt->js1_pov_hat = -1; + opt->js1_axis_brake_left = -1; + opt->js1_axis_brake_right = -1; + + /* No need to initialize + * opt->js2_sdl_name + */ + strcpy(opt->js2_sdl_guid_s, ""); + opt->js2_btn_rotate = -1; + opt->js2_btn_air_brakes = -1; + opt->js2_btn_wheel_brakes = -1; + opt->js2_btn_zoom_in = -1; + opt->js2_btn_zoom_out = -1; + opt->js2_btn_hoist_up = -1; + opt->js2_btn_hoist_down = -1; + opt->js2_axis_heading = -1; + opt->js2_axis_pitch = -1; + opt->js2_axis_bank = -1; + opt->js2_axis_throttle = -1; + opt->js2_axis_hat_x = -1; + opt->js2_axis_hat_y = -1; + opt->js2_pov_hat = -1; + opt->js2_axis_brake_left = -1; + opt->js2_axis_brake_right = -1; + + opt->js_axes_inversion_bits = 0; opt->hoist_contact_expansion_coeff = 1.0f; opt->damage_resistance_coeff = 1.0f; @@ -2381,6 +2463,12 @@ void SARShutdown(sar_core_struct *core_ptr) s ); } + if(opt->js0_sdl_name != NULL) + free(opt->js0_sdl_name); + if(opt->js1_sdl_name != NULL) + free(opt->js1_sdl_name); + if(opt->js2_sdl_name != NULL) + free(opt->js2_sdl_name); /* Save players list */ s = fname.players; if(!STRISEMPTY(s)) @@ -2582,6 +2670,7 @@ void SARShutdown(sar_core_struct *core_ptr) /* Game Controller */ GCtlDelete(core_ptr->gctl); core_ptr->gctl = NULL; + SDL_Quit(); /* Music List */ SARMusicListDeleteAll(&core_ptr->music_ref, &core_ptr->total_music_refs); diff --git a/src/menu.c b/src/menu.c index 5e163a4..1e51620 100644 --- a/src/menu.c +++ b/src/menu.c @@ -61,6 +61,12 @@ int SARMenuLabelNew( sar_menu_color_struct *fg_color, GWFont *font, const sar_image_struct *image ); +int SARMenuLabelSetLabel( + gw_display_struct *display, sar_menu_struct *m, int n, + const char *label, + sar_menu_color_struct *fg_color, + Boolean redraw +); /* Button */ int SARMenuButtonNew( @@ -743,6 +749,59 @@ int SARMenuLabelNew( return(n); } +/* + * Sets a new label label and/or label foreground color + * for label n on menu m. + * + * - Sets label label if *label is not NULL. + * - Sets label foreground color if *fg_color is not NULL. + * - Redraws label if redraw is True. + * + * Returns a negative value on error. + */ +int SARMenuLabelSetLabel( + gw_display_struct *display, sar_menu_struct *m, int n, + const char *label, + sar_menu_color_struct *fg_color, + Boolean redraw +) +{ + sar_menu_label_struct *label_ptr; + + if(m == NULL) + return -1; + if(m->total_objects < n) + return -2; + + label_ptr = SARMenuGetObject(m, n); + if(label_ptr == NULL || label_ptr->type != SAR_MENU_OBJECT_TYPE_LABEL) + return -3; + + /* Set new label label */ + + if(label != NULL){ + free(label_ptr->label); + label_ptr->label = STRDUP(label); + } + + /* Set new label forground color */ + + if(fg_color != NULL) + memcpy(&label_ptr->color, fg_color, sizeof(sar_menu_color_struct)); + + /* Redraw label */ + + if(redraw){ + if(display != NULL){ + DO_REDRAW_OBJECT(display, m, n); + } + else + return -4; + } + + return 0; +} + /* * Allocates a new button on menu m. * @@ -1908,7 +1967,7 @@ void SARMenuSpinDoInc( } /* - * Spin increment procedure. + * Spin decrement procedure. */ void SARMenuSpinDoDec( gw_display_struct *display, sar_menu_struct *m, int n, diff --git a/src/menu.h b/src/menu.h index a28fc91..b10aa81 100644 --- a/src/menu.h +++ b/src/menu.h @@ -640,6 +640,12 @@ extern int SARMenuLabelNew( sar_menu_color_struct *fg_color, GWFont *font, const sar_image_struct *image ); +extern int SARMenuLabelSetLabel( + gw_display_struct *display, sar_menu_struct *m, int n, + const char *label, + sar_menu_color_struct *fg_color, + Boolean redraw +); /* Button */ extern int SARMenuButtonNew( diff --git a/src/optionio.c b/src/optionio.c index 6b73dd2..a9df5bb 100644 --- a/src/optionio.c +++ b/src/optionio.c @@ -53,7 +53,6 @@ int SAROptionsSaveToFile( # define SAR_CFG_DELIM_CHAR '=' #endif - /* * Loads options from file. */ @@ -63,6 +62,7 @@ int SAROptionsLoadFromFile( { FILE *fp; char *buf = NULL; + double version[3]; struct stat stat_buf; @@ -106,9 +106,7 @@ int SAROptionsLoadFromFile( /* Version */ if(!strcasecmp(buf, "Version")) { - double vf[3]; - FGetValuesF(fp, vf, 3); - + FGetValuesF(fp, version, 3); } /* MenuBackgrounds */ @@ -375,6 +373,54 @@ int SAROptionsLoadFromFile( opt->gctl_controllers = (gctl_controllers)vf[0]; } + /* Joystick #1 (js0) SDL_NAME */ + else if(!strcasecmp(buf, "Joystick0Name")) + { + char *s = FGetString(fp); + opt->js0_sdl_name = STRDUP(s); + } + /* Joystick #1 (js0) SDL_GUID */ + else if(!strcasecmp(buf, "Joystick0Guid")) + { + char *s = FGetString(fp); + if(strlen(s) == 32){ + strcpy(opt->js0_sdl_guid_s, s); + } + else + strcpy(opt->js0_sdl_guid_s, ""); + } + /* Joystick #2 (js1) SDL_NAME */ + else if(!strcasecmp(buf, "Joystick1Name")) + { + char *s = FGetString(fp); + opt->js1_sdl_name = STRDUP(s); + } + /* Joystick #2 (js1) SDL_GUID */ + else if(!strcasecmp(buf, "Joystick1Guid")) + { + char *s = FGetString(fp); + if(strlen(s) == 32){ + strcpy(opt->js1_sdl_guid_s, s); + } + else + strcpy(opt->js1_sdl_guid_s, ""); + } + /* Joystick #3 (js2) SDL_NAME */ + else if(!strcasecmp(buf, "Joystick2Name")) + { + char *s = FGetString(fp); + opt->js2_sdl_name = STRDUP(s); + } + /* Joystick #3 (js2) SDL_GUID */ + else if(!strcasecmp(buf, "Joystick2Guid")) + { + char *s = FGetString(fp); + if(strlen(s) == 32){ + strcpy(opt->js2_sdl_guid_s, s); + } + else + strcpy(opt->js2_sdl_guid_s, ""); + } /* Joystick #1 (js0) button mappings */ else if(!strcasecmp(buf, "Joystick0ButtonMappings") || !strcasecmp(buf, "JoystickButtonMappings") @@ -415,21 +461,203 @@ int SAROptionsLoadFromFile( opt->js1_btn_hoist_up = (int)vf[5]; opt->js1_btn_hoist_down = (int)vf[6]; } - /* Joystick #1 (js0) axis roles */ + /* Joystick #3 (js2) button mappings */ + else if(!strcasecmp(buf, "Joystick2ButtonMappings")) + { + /* Format: + * + * + * + */ + double vf[7]; + FGetValuesF(fp, vf, 7); + + opt->js2_btn_rotate = (int)vf[0]; + opt->js2_btn_air_brakes = (int)vf[1]; + opt->js2_btn_wheel_brakes = (int)vf[2]; + opt->js2_btn_zoom_in = (int)vf[3]; + opt->js2_btn_zoom_out = (int)vf[4]; + opt->js2_btn_hoist_up = (int)vf[5]; + opt->js2_btn_hoist_down = (int)vf[6]; + } + /* Joystick #1 (js0) axis roles. + * Should only happen when opening sar2.ini file version <= 2.6.0. + */ else if(!strcasecmp(buf, "Joystick0AxisRoles")) { /* Value is stored as bits (unsigned long) */ double vf[1]; + /* Read value to avoid complain (backward compatibility). */ FGetValuesF(fp, vf, 1); - opt->gctl_js0_axis_roles = (gctl_js_axis_roles)vf[0]; + /* opt->gctl_js0_axis_roles = (gctl_js_axis_roles)vf[0]; */ + + if(vf[0] != 0){ + fprintf(stderr, "It seems that your %s configuration file \ +is not up to date.\nPlease go to Options/Controller/Joystick then remap your \ +joystick(s).\n", filename); + + /* Reset old sar2.ini file version values */ + opt->js0_btn_rotate = -1; + opt->js0_btn_air_brakes = -1; + opt->js0_btn_wheel_brakes = -1; + opt->js0_btn_zoom_in = -1; + opt->js0_btn_zoom_out = -1; + opt->js0_btn_hoist_up = -1; + opt->js0_btn_hoist_down = -1; + opt->js0_pov_hat = -1; + + opt->js1_btn_rotate = -1; + opt->js1_btn_air_brakes = -1; + opt->js1_btn_wheel_brakes = -1; + opt->js1_btn_zoom_in = -1; + opt->js1_btn_zoom_out = -1; + opt->js1_btn_hoist_up = -1; + opt->js1_btn_hoist_down = -1; + opt->js1_pov_hat = -1; + + /* No need to reset js0/1/2 axis mappings and js2 buttons + * values because they don't exist in old sar2.ini files. + */ + } } - /* Joystick #2 (js1) axis roles */ + /* Joystick #2 (js1) axis roles. Sar2 versions <= 2.6.0 only! */ else if(!strcasecmp(buf, "Joystick1AxisRoles")) { /* Value is stored as bits (unsigned long) */ double vf[1]; + /* Read value to avoid complain (backward compatibility). */ FGetValuesF(fp, vf, 1); - opt->gctl_js1_axis_roles = (gctl_js_axis_roles)vf[0]; + /* opt->gctl_js1_axis_roles = (gctl_js_axis_roles)vf[0]; */ + } + /* Joystick #1 (js0) axes mappings */ + else if(!strcasecmp(buf, "Joystick0AxisMappings")) + { + /* Format: + * + * + * + */ + int value[9]; + FGetValuesI(fp, value, 9); + + opt->js0_axis_heading = value[0]; + opt->js0_axis_pitch = value[1]; + opt->js0_axis_bank = value[2]; + opt->js0_axis_throttle = value[3]; + opt->js0_axis_hat_x = value[4]; + opt->js0_axis_hat_y = value[5]; + opt->js0_pov_hat = value[6]; + opt->js0_axis_brake_left = value[7]; + opt->js0_axis_brake_right = value[8]; + } + /* Joystick #2 (js1) axes mappings */ + else if(!strcasecmp(buf, "Joystick1AxisMappings")) + { + /* Format: + * + * + * + */ + int value[9]; + FGetValuesI(fp, value, 9); + + opt->js1_axis_heading = value[0]; + opt->js1_axis_pitch = value[1]; + opt->js1_axis_bank = value[2]; + opt->js1_axis_throttle = value[3]; + opt->js1_axis_hat_x = value[4]; + opt->js1_axis_hat_y = value[5]; + opt->js1_pov_hat = value[6]; + opt->js1_axis_brake_left = value[7]; + opt->js1_axis_brake_right = value[8]; + } + /* Joystick #3 (js2) axes mappings */ + else if(!strcasecmp(buf, "Joystick2AxisMappings")) + { + /* Format: + * + * + * + */ + int value[9]; + FGetValuesI(fp, value, 9); + + opt->js2_axis_heading = value[0]; + opt->js2_axis_pitch = value[1]; + opt->js2_axis_bank = value[2]; + opt->js2_axis_throttle = value[3]; + opt->js2_axis_hat_x = value[4]; + opt->js2_axis_hat_y = value[5]; + opt->js2_pov_hat = value[6]; + opt->js2_axis_brake_left = value[7]; + opt->js2_axis_brake_right = value[8]; + } + /* Joysticks axis inversion */ + else if(!strcasecmp(buf, "JoysticksAxisInversion")) + { + /* Format: + * + * + * + */ + int value[9]; + FGetValuesI(fp, value, 9); + + opt->js_axes_inversion_bits = 0; + + /* Heading */ + if(value[0] == 1) + opt->js_axes_inversion_bits |= GCTL_JS_AXIS_INV_HEADING; + else + opt->js_axes_inversion_bits &= ~GCTL_JS_AXIS_INV_HEADING; + + /* Pitch */ + if(value[1] == 1) + opt->js_axes_inversion_bits |= GCTL_JS_AXIS_INV_PITCH; + else + opt->js_axes_inversion_bits &= ~GCTL_JS_AXIS_INV_PITCH; + + /* Bank */ + if(value[2] == 1) + opt->js_axes_inversion_bits |= GCTL_JS_AXIS_INV_BANK; + else + opt->js_axes_inversion_bits &= ~GCTL_JS_AXIS_INV_BANK; + + /* Throttle */ + if(value[3] == 1) + opt->js_axes_inversion_bits |= GCTL_JS_AXIS_INV_THROTTLE; + else + opt->js_axes_inversion_bits &= ~GCTL_JS_AXIS_INV_THROTTLE; + + /* Hat x */ + if(value[4] == 1) + opt->js_axes_inversion_bits |= GCTL_JS_AXIS_INV_HAT_X; + else + opt->js_axes_inversion_bits &= ~GCTL_JS_AXIS_INV_HAT_X; + + /* Hat y */ + if(value[5] == 1) + opt->js_axes_inversion_bits |= GCTL_JS_AXIS_INV_HAT_Y; + else + opt->js_axes_inversion_bits &= ~GCTL_JS_AXIS_INV_HAT_Y; + + /* POV Hat */ + if(value[6] == 1) + opt->js_axes_inversion_bits |= GCTL_JS_AXIS_INV_POV_HAT; + else + opt->js_axes_inversion_bits &= ~GCTL_JS_AXIS_INV_POV_HAT; + + /* Brake left */ + if(value[7] == 1) + opt->js_axes_inversion_bits |= GCTL_JS_AXIS_INV_BRAKE_LEFT; + else + opt->js_axes_inversion_bits &= ~GCTL_JS_AXIS_INV_BRAKE_LEFT; + + /* Brake right */ + if(value[8] == 1) + opt->js_axes_inversion_bits |= GCTL_JS_AXIS_INV_BRAKE_RIGHT; + else + opt->js_axes_inversion_bits &= ~GCTL_JS_AXIS_INV_BRAKE_RIGHT; } /* GameControllerOptions */ else if(!strcasecmp(buf, "GameControllerOptions")) @@ -823,8 +1051,9 @@ int SAROptionsSaveToFile( opt->rotor_wash_vis_coeff ); PUTCR + PUTCR - /* Game controllers mask (was GameControllerType) */ + /* Game controllers mask */ fprintf( fp, "# Mask of game controllers; (1 << 0) = keyboard, (1 << 1) = pointer," @@ -841,50 +1070,250 @@ int SAROptionsSaveToFile( opt->gctl_controllers ); PUTCR - /* Joystick button mappings (7 values) */ fprintf( fp, -"\ -# Joystick button mappings: \n\ -# " + "# Joystick name and SDL GUID. SDL GUID must be unique." ); PUTCR + if(opt->js0_sdl_name != NULL && strlen(opt->js0_sdl_guid_s) != 0) + fprintf( + fp, + "Joystick0Name = %s", + opt->js0_sdl_name + ); + else + fprintf( + fp, + "Joystick0Name = " + ); + PUTCR + fprintf( + fp, + "Joystick0Guid = %s", + opt->js0_sdl_guid_s + ); + PUTCR + if(opt->js1_sdl_name != NULL && strlen(opt->js1_sdl_guid_s) != 0) + fprintf( + fp, + "Joystick1Name = %s", + opt->js1_sdl_name + ); + else + fprintf( + fp, + "Joystick1Name = " + ); + PUTCR fprintf( fp, - "Joystick0ButtonMappings = %i %i %i %i %i %i %i", - opt->js0_btn_rotate, - opt->js0_btn_air_brakes, - opt->js0_btn_wheel_brakes, - opt->js0_btn_zoom_in, - opt->js0_btn_zoom_out, - opt->js0_btn_hoist_up, - opt->js0_btn_hoist_down + "Joystick1Guid = %s", + opt->js1_sdl_guid_s ); PUTCR + if(opt->js2_sdl_name != NULL && strlen(opt->js2_sdl_guid_s) != 0) + fprintf( + fp, + "Joystick2Name = %s", + opt->js2_sdl_name + ); + else + fprintf( + fp, + "Joystick2Name = " + ); + PUTCR fprintf( fp, - "Joystick1ButtonMappings = %i %i %i %i %i %i %i", - opt->js1_btn_rotate, - opt->js1_btn_air_brakes, - opt->js1_btn_wheel_brakes, - opt->js1_btn_zoom_in, - opt->js1_btn_zoom_out, - opt->js1_btn_hoist_up, - opt->js1_btn_hoist_down + "Joystick2Guid = %s", + opt->js2_sdl_guid_s ); PUTCR - /* Joystick axis roles */ + /* Joystick button mappings (7 values) */ fprintf( fp, - "Joystick0AxisRoles = %i", - opt->gctl_js0_axis_roles +"\ +# Joystick button mappings.\n\ +# Set button number between 0 and 15 included if role is assigned,\n\ +# or set to -1 if role is not assigned.\n\ +# " ); PUTCR + if(strlen(opt->js0_sdl_guid_s)!= 0) + fprintf( + fp, + "Joystick0ButtonMappings = %2i %2i %2i %2i %2i %2i %2i", + opt->js0_btn_rotate, + opt->js0_btn_air_brakes, + opt->js0_btn_wheel_brakes, + opt->js0_btn_zoom_in, + opt->js0_btn_zoom_out, + opt->js0_btn_hoist_up, + opt->js0_btn_hoist_down + ); + else + fprintf( + fp, + "Joystick0ButtonMappings = -1 -1 -1 -1 -1 -1 -1" + ); + PUTCR + if(strlen(opt->js1_sdl_guid_s)!= 0) + fprintf( + fp, + "Joystick1ButtonMappings = %2i %2i %2i %2i %2i %2i %2i", + opt->js1_btn_rotate, + opt->js1_btn_air_brakes, + opt->js1_btn_wheel_brakes, + opt->js1_btn_zoom_in, + opt->js1_btn_zoom_out, + opt->js1_btn_hoist_up, + opt->js1_btn_hoist_down + ); + else + fprintf( + fp, + "Joystick1ButtonMappings = -1 -1 -1 -1 -1 -1 -1" + ); + PUTCR + if(strlen(opt->js2_sdl_guid_s)!= 0) + fprintf( + fp, + "Joystick2ButtonMappings = %2i %2i %2i %2i %2i %2i %2i", + opt->js2_btn_rotate, + opt->js2_btn_air_brakes, + opt->js2_btn_wheel_brakes, + opt->js2_btn_zoom_in, + opt->js2_btn_zoom_out, + opt->js2_btn_hoist_up, + opt->js2_btn_hoist_down + ); + else + fprintf( + fp, + "Joystick2ButtonMappings = -1 -1 -1 -1 -1 -1 -1" + ); + PUTCR + /* Joystick axes mappings (9 values) */ fprintf( fp, - "Joystick1AxisRoles = %i", - opt->gctl_js1_axis_roles +"\ +# Joystick axis mappings.\n\ +# Set axis number between 0 and 7 included if role is assigned,\n\ +# or set to -1 if role is not assigned.\n\ +# If POV control use a standard POV hat switch,\n\ +# set and to -1 and to hat number (0 or 1).\n\ +# If POV control use analog axes,\n\ +# set and to axis number and to -1.\n\ +# If axis direction must be inverted, set corresponding inversion value to 1.\n\ +# " ); + PUTCR + if(strlen(opt->js0_sdl_guid_s)!= 0) + fprintf( + fp, + "Joystick0AxisMappings = %2i %2i %2i %2i %2i %2i %2i %2i %2i", + opt->js0_axis_heading, + opt->js0_axis_pitch, + opt->js0_axis_bank, + opt->js0_axis_throttle, + opt->js0_axis_hat_x, + opt->js0_axis_hat_y, + opt->js0_pov_hat, + opt->js0_axis_brake_left, + opt->js0_axis_brake_right + ); + else + fprintf( + fp, + "Joystick0AxisMappings = -1 -1 -1 -1 -1 -1 -1 -1 -1" + ); + PUTCR + if(strlen(opt->js1_sdl_guid_s)!= 0) + fprintf( + fp, + "Joystick1AxisMappings = %2i %2i %2i %2i %2i %2i %2i %2i %2i", + opt->js1_axis_heading, + opt->js1_axis_pitch, + opt->js1_axis_bank, + opt->js1_axis_throttle, + opt->js1_axis_hat_x, + opt->js1_axis_hat_y, + opt->js1_pov_hat, + opt->js1_axis_brake_left, + opt->js1_axis_brake_right + ); + else + fprintf( + fp, + "Joystick1AxisMappings = -1 -1 -1 -1 -1 -1 -1 -1 -1" + ); + PUTCR + if(strlen(opt->js2_sdl_guid_s)!= 0) + fprintf( + fp, + "Joystick2AxisMappings = %2i %2i %2i %2i %2i %2i %2i %2i %2i", + opt->js2_axis_heading, + opt->js2_axis_pitch, + opt->js2_axis_bank, + opt->js2_axis_throttle, + opt->js2_axis_hat_x, + opt->js2_axis_hat_y, + opt->js2_pov_hat, + opt->js2_axis_brake_left, + opt->js2_axis_brake_right + ); + else + fprintf( + fp, + "Joystick2AxisMappings = -1 -1 -1 -1 -1 -1 -1 -1 -1" + ); + PUTCR + + fprintf(fp, "JoysticksAxisInversion ="); + if( strlen(opt->js0_sdl_guid_s) != 0 || + strlen(opt->js1_sdl_guid_s) != 0 || + strlen(opt->js2_sdl_guid_s) != 0 + ){ + if(opt->js_axes_inversion_bits & GCTL_JS_AXIS_INV_HEADING) + fprintf(fp, " 1"); + else + fprintf(fp, " 0"); + if(opt->js_axes_inversion_bits & GCTL_JS_AXIS_INV_PITCH) + fprintf(fp, " 1"); + else + fprintf(fp, " 0"); + if(opt->js_axes_inversion_bits & GCTL_JS_AXIS_INV_BANK) + fprintf(fp, " 1"); + else + fprintf(fp, " 0"); + if(opt->js_axes_inversion_bits & GCTL_JS_AXIS_INV_THROTTLE) + fprintf(fp, " 1"); + else + fprintf(fp, " 0"); + if(opt->js_axes_inversion_bits & GCTL_JS_AXIS_INV_HAT_X) + fprintf(fp, " 1"); + else + fprintf(fp, " 0"); + if(opt->js_axes_inversion_bits & GCTL_JS_AXIS_INV_HAT_Y) + fprintf(fp, " 1"); + else + fprintf(fp, " 0"); + if(opt->js_axes_inversion_bits & GCTL_JS_AXIS_INV_POV_HAT) + fprintf(fp, " 1"); + else + fprintf(fp, " 0"); + if(opt->js_axes_inversion_bits & GCTL_JS_AXIS_INV_BRAKE_LEFT) + fprintf(fp, " 1"); + else + fprintf(fp, " 0"); + if(opt->js_axes_inversion_bits & GCTL_JS_AXIS_INV_BRAKE_RIGHT) + fprintf(fp, " 1"); + else + fprintf(fp, " 0"); + } + else + fprintf(fp, " 0 0 0 0 0 0 0 0 0"); + PUTCR /* Game controller options */ fprintf( diff --git a/src/sar.h b/src/sar.h index 3cac350..2502ae5 100644 --- a/src/sar.h +++ b/src/sar.h @@ -171,8 +171,24 @@ typedef struct { /* Game controller options mask */ gctl_options gctl_options; + /* SDL_GUID, in ASCII string representation. + * If this string is filled, it means that joystick is mapped + * to one or more action(s). + */ + char js0_sdl_guid_s[32+1], + js1_sdl_guid_s[32+1], + js2_sdl_guid_s[32+1]; + + /* Joystick name. + * Name is only given to help player for joystick configuration, + * no treatment is made on it. + */ + char *js0_sdl_name, + *js1_sdl_name, + *js2_sdl_name; + /* Joystick button mappings */ - int js0_btn_rotate, /* Treat bank to heading axis */ + int js0_btn_rotate, /* Treat bank as heading axis */ js0_btn_air_brakes, js0_btn_wheel_brakes, js0_btn_zoom_in, @@ -188,14 +204,50 @@ typedef struct { js1_btn_hoist_up, js1_btn_hoist_down; - /* Game controller joystick axis roles, any of - * GCTL_JS_AXIS_ROLE_* - * - * If any of these are all 0 then that implies the joystick is - * not enabled + int js2_btn_rotate, /* Treat bank as heading axis */ + js2_btn_air_brakes, + js2_btn_wheel_brakes, + js2_btn_zoom_in, + js2_btn_zoom_out, + js2_btn_hoist_up, + js2_btn_hoist_down; + + + /* Axes inversion bits. Bit 0 for axis 0, and so on... + * Each corresponding bit is set if axis movement must be inverted. */ - gctl_js_axis_roles gctl_js0_axis_roles, - gctl_js1_axis_roles; + gctl_js_axes_inversion_bits js_axes_inversion_bits; + + /* Joystick axis mappings */ + int js0_axis_heading, + js0_axis_pitch, + js0_axis_bank, + js0_axis_throttle, + js0_axis_hat_x, + js0_axis_hat_y, + js0_pov_hat, + js0_axis_brake_left, + js0_axis_brake_right; + + int js1_axis_heading, + js1_axis_pitch, + js1_axis_bank, + js1_axis_throttle, + js1_axis_hat_x, + js1_axis_hat_y, + js1_pov_hat, + js1_axis_brake_left, + js1_axis_brake_right; + + int js2_axis_heading, + js2_axis_pitch, + js2_axis_bank, + js2_axis_throttle, + js2_axis_hat_x, + js2_axis_hat_y, + js2_pov_hat, + js2_axis_brake_left, + js2_axis_brake_right; /* Simulation difficulty */ float hoist_contact_expansion_coeff; /* Hoist contact radius coeff */ diff --git a/src/sarmenubuild.c b/src/sarmenubuild.c index 353e042..99c6b53 100644 --- a/src/sarmenubuild.c +++ b/src/sarmenubuild.c @@ -2351,58 +2351,24 @@ int btn_width_map = 32, btn_height_map = 32; SARBuildMenusAddToList(core_ptr, menu); menu->always_full_redraw = opt->menu_always_full_redraw; - /* First joystick (js0) axis roles */ - spin_num = SARMenuBuildStandardSpin( - core_ptr, menu, 0.50f, 0.26f, 0.9f, 0.0f, - "Joystick #1 Axises", SAR_MENU_ID_OPT_JS0_AXISES, - SARMenuOptionsSpinCB - ); - if(spin_num > -1) - { - spin = SAR_MENU_SPIN(menu->object[spin_num]); - spin->allow_warp = False; - SARMenuSpinAddValue(menu, spin_num, "Off"); - SARMenuSpinAddValue(menu, spin_num, "2D"); - SARMenuSpinAddValue(menu, spin_num, "2D with throttle"); - SARMenuSpinAddValue(menu, spin_num, "2D with hat"); - SARMenuSpinAddValue(menu, spin_num, "2D with throttle & hat"); - SARMenuSpinAddValue(menu, spin_num, "3D"); - SARMenuSpinAddValue(menu, spin_num, "3D with throttle"); - SARMenuSpinAddValue(menu, spin_num, "3D with hat"); - SARMenuSpinAddValue(menu, spin_num, "3D with throttle & hat"); - SARMenuSpinAddValue(menu, spin_num, "As throttle & rudder"); - SARMenuSpinAddValue(menu, spin_num, "As rudder & wheel brakes"); - } - - /* Second joystick (js1) axis roles */ - spin_num = SARMenuBuildStandardSpin( - core_ptr, menu, 0.50f, 0.55f, 0.9f, 0.0f, - "Joystick #2 Axises", SAR_MENU_ID_OPT_JS1_AXISES, - SARMenuOptionsSpinCB + /* Go to Joystick test and mapping */ + btn_num = SARMenuBuildStandardButton( + core_ptr, menu, 0.28f, 0.20f, btn_width_opt, btn_height_opt, + True, + " Joystick... ", SAR_MENU_ID_GOTO_OPTIONS_CONTROLLER_JOYSTICK ); - if(spin_num > -1) - { - spin = SAR_MENU_SPIN(menu->object[spin_num]); - spin->allow_warp = False; - SARMenuSpinAddValue(menu, spin_num, "Off"); - SARMenuSpinAddValue(menu, spin_num, "2D"); - SARMenuSpinAddValue(menu, spin_num, "2D with throttle"); - SARMenuSpinAddValue(menu, spin_num, "2D with hat"); - SARMenuSpinAddValue(menu, spin_num, "2D with throttle & hat"); - SARMenuSpinAddValue(menu, spin_num, "3D"); - SARMenuSpinAddValue(menu, spin_num, "3D with throttle"); - SARMenuSpinAddValue(menu, spin_num, "3D with hat"); - SARMenuSpinAddValue(menu, spin_num, "3D with throttle & hat"); - SARMenuSpinAddValue(menu, spin_num, "As throttle & rudder"); - SARMenuSpinAddValue(menu, spin_num, "As rudder & wheel brakes"); - } - - /* Test Joystick Button */ + /* Go to Keyboard mapping */ + /* This button is set to not sensitive because this option is + * not yet available. + * Current sar2 QWERTY layout can cause some problems, especially for + * wheel brakes keys (period and shift+period, i.e. '.' and '>'), which + * positions are radically different on (at least) an AZERTY keyboard. + */ btn_num = SARMenuBuildStandardButton( - core_ptr, menu, 0.75f, 0.74f, btn_width_std, btn_height_std, - True, - "Test...", SAR_MENU_ID_GOTO_OPTIONS_CONTROLLER_TEST + core_ptr, menu, 0.28f, 0.33f, btn_width_opt, btn_height_opt, + False, + " Keyboard... ", SAR_MENU_ID_GOTO_OPTIONS_CONTROLLER_KB_MAPPING ); /* Back Button */ @@ -2412,7 +2378,7 @@ int btn_width_map = 32, btn_height_map = 32; #if defined(PROG_LANGUAGE_SPANISH) "Espalda" #elif defined(PROG_LANGUAGE_FRENCH) -"Dos" +"Retour" #elif defined(PROG_LANGUAGE_GERMAN) "Zurück" #elif defined(PROG_LANGUAGE_ITALIAN) @@ -2429,20 +2395,84 @@ int btn_width_map = 32, btn_height_map = 32; , SAR_MENU_ID_GOTO_OPTIONS ); - /* Joystick Button Mapping Button */ - btn_num = SARMenuBuildStandardButton( + + /* ****************************************************** */ + /* Menu: Options->Controller->Joystick */ + img_path = SARMenuBuildGetFullPath(SAR_DEF_MENU_BGIMG_STANDARD_FILE); + menu = SARMenuNew( + SAR_MENU_TYPE_STANDARD, + SAR_MENU_NAME_OPTIONS_CONTROLLER_JOYSTICK, + img_path + ); + if(menu == NULL) + return(-1); + else + SARBuildMenusAddToList(core_ptr, menu); + menu->always_full_redraw = opt->menu_always_full_redraw; + + /* Joystick Output Display */ + SARMenuMDisplayNew( + menu, 0.50f, 0.40f, 0.95f, 0.72f, + (const sar_image_struct **)core_ptr->menu_list_bg_img, + core_ptr, SAR_MENU_ID_OPT_JS_TEST_UPDATE, + SARMenuOptionsJoystickTestDrawCB + ); + + /* Joystick Mapping Button */ + SARMenuBuildStandardButton( core_ptr, menu, 0.75f, 0.92f, btn_width_std, btn_height_std, True, - "Buttons", SAR_MENU_ID_GOTO_OPTIONS_CONTROLLER_JS_BTN +#if defined(PROG_LANGUAGE_SPANISH) +"Mapping" +#elif defined(PROG_LANGUAGE_FRENCH) +"Mapping" +#elif defined(PROG_LANGUAGE_GERMAN) +"Mapping" +#elif defined(PROG_LANGUAGE_ITALIAN) +"Mapping" +#elif defined(PROG_LANGUAGE_DUTCH) +"Mapping" +#elif defined(PROG_LANGUAGE_PORTUGUESE) +"Mapping" +#elif defined(PROG_LANGUAGE_NORWEGIAN) +"Mapping" +#else +"Mapping" +#endif + , SAR_MENU_ID_GOTO_OPTIONS_CONTROLLER_JS_MAPPING + ); + + /* Back Button */ + SARMenuBuildStandardButton( + core_ptr, menu, 0.25f, 0.92f, btn_width_std, btn_height_std, + True, +#if defined(PROG_LANGUAGE_SPANISH) +"Espalda" +#elif defined(PROG_LANGUAGE_FRENCH) +"Retour" +#elif defined(PROG_LANGUAGE_GERMAN) +"Zurück" +#elif defined(PROG_LANGUAGE_ITALIAN) +"Dorso" +#elif defined(PROG_LANGUAGE_DUTCH) +"Rug" +#elif defined(PROG_LANGUAGE_PORTUGUESE) +"Costas" +#elif defined(PROG_LANGUAGE_NORWEGIAN) +"Frem" +#else +"Back" +#endif + , SAR_MENU_ID_GOTO_OPTIONS_CONTROLLER ); /* ****************************************************** */ - /* Menu: Options->Controller->Buttons */ + /* Menu: Options->Controller->Joystick->Mapping */ img_path = SARMenuBuildGetFullPath(SAR_DEF_MENU_BGIMG_STANDARD_FILE); menu = SARMenuNew( SAR_MENU_TYPE_STANDARD, - SAR_MENU_NAME_OPTIONS_CONTROLLER_JS_BTN, + SAR_MENU_NAME_OPTIONS_CONTROLLER_JS_MAPPING, img_path ); if(menu == NULL) @@ -2451,145 +2481,411 @@ int btn_width_map = 32, btn_height_map = 32; SARBuildMenusAddToList(core_ptr, menu); menu->always_full_redraw = opt->menu_always_full_redraw; - /* Joystick 1 (js0) button action spin */ + /* Help label #1 + * This label text must start with "1) " because this is used to + * detect this label on the joystick mapping menu in order to change + * label color. Look for '!strstr(label->label, "1) "' + * in SARMenuManageOptionsControllerJSMapping(). + * This restriction is necessary only for this menu and, of course, + * no other label text on this menu shouldn't start with "1) ". + * + * Note that labels are always center aligned thus label text width + * and number of lines are important. + */ + label_num = SARMenuLabelNew( + menu, 0.50f, 0.03f, 0, 0, +#if defined(PROG_LANGUAGE_SPANISH) +"1) Haga clic en un cuadro de funcion para seleccionar la funcion a asignar. " +#elif defined(PROG_LANGUAGE_FRENCH) +"1) Cliquez sur une boite de role pour selectionner le role a definir. " +#elif defined(PROG_LANGUAGE_GERMAN) +"1) Klicken Sie auf ein Rollenfeld, um die zuzuordnende Rolle auszuwahlen. " +#elif defined(PROG_LANGUAGE_ITALIAN) +"1) Fare clic su una casella di ruolo per selezionare il ruolo da mappare. " +#elif defined(PROG_LANGUAGE_DUTCH) +"1) Klik op een rolvak om de rol te selecteren die u wilt toewijzen. " +#elif defined(PROG_LANGUAGE_PORTUGUESE) +"1) Clique numa caixa de funcao para selecionar a funçao a mapear. " +#elif defined(PROG_LANGUAGE_NORWEGIAN) +"1) Klik op een rolvak om de rol te selecteren die u wilt toewijzen. " +#else +"1) Click on a role box to select the role to map. " +#endif + , &label_color, font, + NULL /* No background image */ + ); + if(label_num > -1) + { + sar_menu_label_struct *label = SAR_MENU_LABEL( + menu->object[label_num] + ); + label->align = SAR_MENU_LABEL_ALIGN_LEFT; + } + + /* Help label #2 + * This label text must start with "2) " because this is used to + * detect this label on the joystick mapping menu in order to change + * label color and text. Look for '!strstr(label->label, "2) "' + * in SARMenuManageOptionsControllerJSMapping(). + * This restriction is necessary only for this menu and, of course, + * no other label text on this menu shouldn't start with "2) ". + * + * Note that this label text and label color will be modified by + * SARMenuManageOptionsControllerJSMapping() thus only the 3 first + * characters are set here in order to allow future label detection. + */ + label_num = SARMenuLabelNew( + menu, 0.50f, 0.09f, 0, 0, + "2) ", + &label_color, font, + NULL /* No background image */ + ); + if(label_num > -1) + { + sar_menu_label_struct *label = SAR_MENU_LABEL( + menu->object[label_num] + ); + label->align = SAR_MENU_LABEL_ALIGN_LEFT; + } + + /* Joystick axes mapping */ + /* Axes values start from spin value - 1, since spin + * value 0 really means axis -1 (none) + */ +#define JS_AXIS_MAPPING_SPIN_VALUES \ +SARMenuSpinAddValue(menu, spin_num, "None");\ +SARMenuSpinAddValue(menu, spin_num, "Joystick 1 - Axis 1");\ +SARMenuSpinAddValue(menu, spin_num, "Joystick 1 - Axis 2");\ +SARMenuSpinAddValue(menu, spin_num, "Joystick 1 - Axis 3");\ +SARMenuSpinAddValue(menu, spin_num, "Joystick 1 - Axis 4");\ +SARMenuSpinAddValue(menu, spin_num, "Joystick 1 - Axis 5");\ +SARMenuSpinAddValue(menu, spin_num, "Joystick 1 - Axis 6");\ +SARMenuSpinAddValue(menu, spin_num, "Joystick 1 - Axis 7");\ +SARMenuSpinAddValue(menu, spin_num, "Joystick 1 - Axis 8");\ +SARMenuSpinAddValue(menu, spin_num, "Joystick 2 - Axis 1");\ +SARMenuSpinAddValue(menu, spin_num, "Joystick 2 - Axis 2");\ +SARMenuSpinAddValue(menu, spin_num, "Joystick 2 - Axis 3");\ +SARMenuSpinAddValue(menu, spin_num, "Joystick 2 - Axis 4");\ +SARMenuSpinAddValue(menu, spin_num, "Joystick 2 - Axis 5");\ +SARMenuSpinAddValue(menu, spin_num, "Joystick 2 - Axis 6");\ +SARMenuSpinAddValue(menu, spin_num, "Joystick 2 - Axis 7");\ +SARMenuSpinAddValue(menu, spin_num, "Joystick 2 - Axis 8");\ +SARMenuSpinAddValue(menu, spin_num, "Joystick 3 - Axis 1");\ +SARMenuSpinAddValue(menu, spin_num, "Joystick 3 - Axis 2");\ +SARMenuSpinAddValue(menu, spin_num, "Joystick 3 - Axis 3");\ +SARMenuSpinAddValue(menu, spin_num, "Joystick 3 - Axis 4");\ +SARMenuSpinAddValue(menu, spin_num, "Joystick 3 - Axis 5");\ +SARMenuSpinAddValue(menu, spin_num, "Joystick 3 - Axis 6");\ +SARMenuSpinAddValue(menu, spin_num, "Joystick 3 - Axis 7");\ +SARMenuSpinAddValue(menu, spin_num, "Joystick 3 - Axis 8"); + +#define MAPPING_SPIN_WIDTH 0.455f +#define XPOS 0.23f + float ypos = 0.20f; +#define LASTYPOS ypos +#define NEXTYPOS ypos+=0.07f + + /* Joystick axes spins column label */ + label_num = SARMenuLabelNew( + menu, XPOS, 0.15f, 0, 0, +#if defined(PROG_LANGUAGE_SPANISH) +"Eje" +#elif defined(PROG_LANGUAGE_FRENCH) +"Axes" +#elif defined(PROG_LANGUAGE_GERMAN) +"Achse" +#elif defined(PROG_LANGUAGE_ITALIAN) +"Asse" +#elif defined(PROG_LANGUAGE_DUTCH) +"Assen" +#elif defined(PROG_LANGUAGE_PORTUGUESE) +"Eixo" +#elif defined(PROG_LANGUAGE_NORWEGIAN) +"Akse" +#else +"Axes" +#endif + , &label_color, font, + NULL /* No background image */ + ); + if(label_num > -1) + { + sar_menu_label_struct *label = SAR_MENU_LABEL( + menu->object[label_num] + ); + label->align = SAR_MENU_LABEL_ALIGN_LEFT; + } + + + /* Axes inversion switches column label */ + label_num = SARMenuLabelNew( + menu, XPOS + 0.24f, 0.15f, 0, 0, +#if defined(PROG_LANGUAGE_SPANISH) +"Recambiar" +#elif defined(PROG_LANGUAGE_FRENCH) +"Inverser" +#elif defined(PROG_LANGUAGE_GERMAN) +"Invertieren" +#elif defined(PROG_LANGUAGE_ITALIAN) +"Invertire" +#elif defined(PROG_LANGUAGE_DUTCH) +"Omkeren" +#elif defined(PROG_LANGUAGE_PORTUGUESE) +"Invertido" +#elif defined(PROG_LANGUAGE_NORWEGIAN) +"Invertere" +#else +"Invert" +#endif + , &label_color, font, + NULL /* No background image */ + ); + if(label_num > -1) + { + sar_menu_label_struct *label = SAR_MENU_LABEL( + menu->object[label_num] + ); + label->align = SAR_MENU_LABEL_ALIGN_LEFT; + } + + /* Heading axis mapping spin */ spin_num = SARMenuBuildStandardSpin( - core_ptr, menu, 0.5f, 0.14f, 0.9f, 0.0f, - "Joystick #1 Action", SAR_MENU_ID_OPT_JS0_BUTTON_ACTION, + core_ptr, menu, XPOS, ypos, MAPPING_SPIN_WIDTH, 0.0f, + "Heading ", SAR_MENU_ID_OPT_HEADING_AXIS, SARMenuOptionsSpinCB ); if(spin_num > -1) { spin = SAR_MENU_SPIN(menu->object[spin_num]); spin->allow_warp = False; - SARMenuSpinAddValue(menu, spin_num, "Rotate Modifier"); - SARMenuSpinAddValue(menu, spin_num, "Air Brakes"); - SARMenuSpinAddValue(menu, spin_num, "Wheel Brakes"); - SARMenuSpinAddValue(menu, spin_num, "Zoom In"); - SARMenuSpinAddValue(menu, spin_num, "Zoom Out"); - SARMenuSpinAddValue(menu, spin_num, "Hoist Up"); - SARMenuSpinAddValue(menu, spin_num, "Hoist Down"); + JS_AXIS_MAPPING_SPIN_VALUES } - /* Joystick 1 (js0) button number spin */ + /* Heading axis inversion Switch */ + SARMenuBuildStandardSwitch( + core_ptr, menu, + XPOS + 0.235f, ypos - 0.032f, + 1, 1, + NULL, /* No text */ + False, SAR_MENU_ID_OPT_HEADING_AXIS_INV, + SARMenuOptionsSwitchCB + ); + + /* Pitch axis mapping spin */ spin_num = SARMenuBuildStandardSpin( - core_ptr, menu, 0.5f, 0.26f, 0.9f, 0.0f, - "Button Number", SAR_MENU_ID_OPT_JS0_BUTTON_NUMBER, + core_ptr, menu, XPOS, NEXTYPOS, MAPPING_SPIN_WIDTH, 0.0f, + "Pitch ", SAR_MENU_ID_OPT_PITCH_AXIS, SARMenuOptionsSpinCB ); if(spin_num > -1) { spin = SAR_MENU_SPIN(menu->object[spin_num]); spin->allow_warp = False; - /* Button values start from spin value - 1, since spin - * value 0 really means button -1 (none) - */ - SARMenuSpinAddValue(menu, spin_num, "None"); - SARMenuSpinAddValue(menu, spin_num, "1"); - SARMenuSpinAddValue(menu, spin_num, "2"); - SARMenuSpinAddValue(menu, spin_num, "3"); - SARMenuSpinAddValue(menu, spin_num, "4"); - SARMenuSpinAddValue(menu, spin_num, "5"); - SARMenuSpinAddValue(menu, spin_num, "6"); - SARMenuSpinAddValue(menu, spin_num, "7"); - SARMenuSpinAddValue(menu, spin_num, "8"); - SARMenuSpinAddValue(menu, spin_num, "9"); - SARMenuSpinAddValue(menu, spin_num, "10"); - SARMenuSpinAddValue(menu, spin_num, "11"); - SARMenuSpinAddValue(menu, spin_num, "12"); - SARMenuSpinAddValue(menu, spin_num, "13"); - SARMenuSpinAddValue(menu, spin_num, "14"); - SARMenuSpinAddValue(menu, spin_num, "15"); - SARMenuSpinAddValue(menu, spin_num, "16"); + JS_AXIS_MAPPING_SPIN_VALUES + } + + /* Pitch axis inversion Switch */ + SARMenuBuildStandardSwitch( + core_ptr, menu, + XPOS + 0.235f, ypos - 0.032f, + 1, 1, + NULL, /* No text */ + False, SAR_MENU_ID_OPT_PITCH_AXIS_INV, + SARMenuOptionsSwitchCB + ); + + /* Bank axis mapping spin */ + spin_num = SARMenuBuildStandardSpin( + core_ptr, menu, XPOS, NEXTYPOS, MAPPING_SPIN_WIDTH, 0.0f, + "Bank ", SAR_MENU_ID_OPT_BANK_AXIS, + SARMenuOptionsSpinCB + ); + if(spin_num > -1) + { + spin = SAR_MENU_SPIN(menu->object[spin_num]); + spin->allow_warp = False; + JS_AXIS_MAPPING_SPIN_VALUES } + /* Bank axis inversion Switch */ + SARMenuBuildStandardSwitch( + core_ptr, menu, + XPOS + 0.235f, ypos - 0.032f, + 1, 1, + NULL, /* No text */ + False, SAR_MENU_ID_OPT_BANK_AXIS_INV, + SARMenuOptionsSwitchCB + ); - /* Joystick 2 (js1) button action spin */ + /* Throttle axis mapping spin */ spin_num = SARMenuBuildStandardSpin( - core_ptr, menu, 0.5f, 0.43f, 0.9f, 0.0f, - "Joystick #2 Action", SAR_MENU_ID_OPT_JS1_BUTTON_ACTION, + core_ptr, menu, XPOS, NEXTYPOS, MAPPING_SPIN_WIDTH, 0.0f, + "Throttle ", SAR_MENU_ID_OPT_THROTTLE_AXIS, SARMenuOptionsSpinCB ); if(spin_num > -1) { spin = SAR_MENU_SPIN(menu->object[spin_num]); spin->allow_warp = False; - SARMenuSpinAddValue(menu, spin_num, "Rotate Modifier"); - SARMenuSpinAddValue(menu, spin_num, "Air Brakes"); - SARMenuSpinAddValue(menu, spin_num, "Wheel Brakes"); - SARMenuSpinAddValue(menu, spin_num, "Zoom In"); - SARMenuSpinAddValue(menu, spin_num, "Zoom Out"); - SARMenuSpinAddValue(menu, spin_num, "Hoist Up"); - SARMenuSpinAddValue(menu, spin_num, "Hoist Down"); + JS_AXIS_MAPPING_SPIN_VALUES } - /* Joystick 2 (js1) button number spin */ + /* Throttle axis inversion Switch */ + SARMenuBuildStandardSwitch( + core_ptr, menu, + XPOS + 0.235f, ypos - 0.032f, + 1, 1, + NULL, /* No text */ + False, SAR_MENU_ID_OPT_THROTTLE_AXIS_INV, + SARMenuOptionsSwitchCB + ); + + /* Brake left axis mapping spin */ spin_num = SARMenuBuildStandardSpin( - core_ptr, menu, 0.5f, 0.55f, 0.9f, 0.0f, - "Button Number", SAR_MENU_ID_OPT_JS1_BUTTON_NUMBER, + core_ptr, menu, XPOS, NEXTYPOS, MAPPING_SPIN_WIDTH, 0.0f, + "Left Brake ", SAR_MENU_ID_OPT_BRAKE_LEFT_AXIS, + SARMenuOptionsSpinCB + ); + if(spin_num > -1) + { + spin = SAR_MENU_SPIN(menu->object[spin_num]); + spin->allow_warp = False; + JS_AXIS_MAPPING_SPIN_VALUES + } + + /* Brake Left axis inversion Switch */ + SARMenuBuildStandardSwitch( + core_ptr, menu, + XPOS + 0.235f, ypos - 0.032f, + 1, 1, + NULL, /* No text */ + False, SAR_MENU_ID_OPT_BRAKE_LEFT_AXIS_INV, + SARMenuOptionsSwitchCB + ); + + /* Brake right axis mapping spin */ + spin_num = SARMenuBuildStandardSpin( + core_ptr, menu, XPOS, NEXTYPOS, MAPPING_SPIN_WIDTH, 0.0f, + "Right Brake", SAR_MENU_ID_OPT_BRAKE_RIGHT_AXIS, + SARMenuOptionsSpinCB + ); + if(spin_num > -1) + { + spin = SAR_MENU_SPIN(menu->object[spin_num]); + spin->allow_warp = False; + JS_AXIS_MAPPING_SPIN_VALUES + } + + /* Brake Right axis inversion Switch */ + SARMenuBuildStandardSwitch( + core_ptr, menu, + XPOS + 0.235f, ypos - 0.032f, + 1, 1, + NULL, /* No text */ + False, SAR_MENU_ID_OPT_BRAKE_RIGHT_AXIS_INV, + SARMenuOptionsSwitchCB + ); + + /* Joystick POV Hat mapping spin */ + spin_num = SARMenuBuildStandardSpin( + core_ptr, menu, XPOS, NEXTYPOS, MAPPING_SPIN_WIDTH, 0.0f, + "POV Hat ", SAR_MENU_ID_OPT_POV_HAT, SARMenuOptionsSpinCB ); - /* Button values start from spin value - 1, since spin - * value 0 really means button -1 (none) - */ if(spin_num > -1) { spin = SAR_MENU_SPIN(menu->object[spin_num]); spin->allow_warp = False; SARMenuSpinAddValue(menu, spin_num, "None"); - SARMenuSpinAddValue(menu, spin_num, "1"); - SARMenuSpinAddValue(menu, spin_num, "2"); - SARMenuSpinAddValue(menu, spin_num, "3"); - SARMenuSpinAddValue(menu, spin_num, "4"); - SARMenuSpinAddValue(menu, spin_num, "5"); - SARMenuSpinAddValue(menu, spin_num, "6"); - SARMenuSpinAddValue(menu, spin_num, "7"); - SARMenuSpinAddValue(menu, spin_num, "8"); - SARMenuSpinAddValue(menu, spin_num, "9"); - SARMenuSpinAddValue(menu, spin_num, "10"); - SARMenuSpinAddValue(menu, spin_num, "11"); - SARMenuSpinAddValue(menu, spin_num, "12"); - SARMenuSpinAddValue(menu, spin_num, "13"); - SARMenuSpinAddValue(menu, spin_num, "14"); - SARMenuSpinAddValue(menu, spin_num, "15"); - SARMenuSpinAddValue(menu, spin_num, "16"); + SARMenuSpinAddValue(menu, spin_num, "Joystick 1 - Hat 1"); + SARMenuSpinAddValue(menu, spin_num, "Joystick 1 - Hat 2"); + SARMenuSpinAddValue(menu, spin_num, "Joystick 2 - Hat 1"); + SARMenuSpinAddValue(menu, spin_num, "Joystick 2 - Hat 2"); + SARMenuSpinAddValue(menu, spin_num, "Joystick 3 - Hat 1"); + SARMenuSpinAddValue(menu, spin_num, "Joystick 3 - Hat 2"); } - /* Label */ + /* Joystick POV Hat inversion Switch */ + SARMenuBuildStandardSwitch( + core_ptr, menu, + XPOS + 0.235f, ypos - 0.032f, + 1, 1, + NULL, /* No text */ + False, SAR_MENU_ID_OPT_POV_HAT_INV, + SARMenuOptionsSwitchCB + ); + + /* Joystick POV X axis mapping spin */ + spin_num = SARMenuBuildStandardSpin( + core_ptr, menu, XPOS, NEXTYPOS, MAPPING_SPIN_WIDTH, 0.0f, + "POV X Axis ", SAR_MENU_ID_OPT_POV_HAT_X, + SARMenuOptionsSpinCB + ); + if(spin_num > -1) + { + spin = SAR_MENU_SPIN(menu->object[spin_num]); + spin->allow_warp = False; + JS_AXIS_MAPPING_SPIN_VALUES + } + + /* Joystick POV X axis inversion Switch */ + SARMenuBuildStandardSwitch( + core_ptr, menu, + XPOS + 0.235f, ypos - 0.032f, + 1, 1, + NULL, /* No text */ + False, SAR_MENU_ID_OPT_POV_HAT_X_INV, + SARMenuOptionsSwitchCB + ); + + /* Joystick POV Y axis mapping spin */ + spin_num = SARMenuBuildStandardSpin( + core_ptr, menu, XPOS, NEXTYPOS, MAPPING_SPIN_WIDTH, 0.0f, + "POV Y Axis ", SAR_MENU_ID_OPT_POV_HAT_Y, + SARMenuOptionsSpinCB + ); + if(spin_num > -1) + { + spin = SAR_MENU_SPIN(menu->object[spin_num]); + spin->allow_warp = False; + JS_AXIS_MAPPING_SPIN_VALUES + } + + /* Joystick POV Y axis inversion Switch */ + SARMenuBuildStandardSwitch( + core_ptr, menu, + XPOS + 0.235f, ypos - 0.032, + 1, 1, + NULL, /* No text */ + False, SAR_MENU_ID_OPT_POV_HAT_Y_INV, + SARMenuOptionsSwitchCB + ); + +#undef JS_AXIS_MAPPING_SPIN_VALUES + +#undef MAPPING_SPIN_WIDTH +#define MAPPING_SPIN_WIDTH 0.495f +#undef XPOS +#define XPOS 0.747f + /* Joystick buttons column label */ label_num = SARMenuLabelNew( - menu, 0.25f, 0.74f, 0, 0, + menu, XPOS, 0.15f, 0, 0, #if defined(PROG_LANGUAGE_SPANISH) -"El botón de palanca de\n\ -mando de prensa para\n\ -trazar el número del\n\ -botón" +"Botones" #elif defined(PROG_LANGUAGE_FRENCH) -"Appuie sur manche à\n\ -balai le bouton pour\n\ -faire la carte du\n\ -numéro de bouton" +"Boutons" #elif defined(PROG_LANGUAGE_GERMAN) -"Presse Steuerknüppel\n\ -Knopf, Knopf Zahl\n\ -aufzuzeichnen" +"Tasten" #elif defined(PROG_LANGUAGE_ITALIAN) -"Premere il bottone\n\ -di leva di comando al\n\ -numero di bottone di\n\ -mappa" +"Pulsanti" #elif defined(PROG_LANGUAGE_DUTCH) -"Pers knuppel knoop\n\ -in kaart knoop nummer\n\ -te brengen" +"Toetsen" #elif defined(PROG_LANGUAGE_PORTUGUESE) -"Apertam botão de\n\ -joystick a número de\n\ -botão de mapa" +"Botões" #elif defined(PROG_LANGUAGE_NORWEGIAN) -"Press joystick button\n\ -to set button number" +"Knapper" #else -"Press joystick button\n\ -to set button number" +"Buttons" #endif , &label_color, font, NULL /* No background image */ @@ -2602,64 +2898,258 @@ to set button number" label->align = SAR_MENU_LABEL_ALIGN_LEFT; } - /* Test Joystick Button */ - btn_num = SARMenuBuildStandardButton( - core_ptr, menu, 0.75f, 0.74f, btn_width_std, btn_height_std, - True, "Test...", SAR_MENU_ID_GOTO_OPTIONS_CONTROLLER_TEST + /* Joystick buttons mapping */ + /* Button values start from spin value - 1, since spin + * value 0 really means button -1 (none) + */ +#define JS_BUTTON_MAPPING_SPIN_VALUES \ +SARMenuSpinAddValue(menu, spin_num, "None");\ +SARMenuSpinAddValue(menu, spin_num, "Joystick 1 - Button 1");\ +SARMenuSpinAddValue(menu, spin_num, "Joystick 1 - Button 2");\ +SARMenuSpinAddValue(menu, spin_num, "Joystick 1 - Button 3");\ +SARMenuSpinAddValue(menu, spin_num, "Joystick 1 - Button 4");\ +SARMenuSpinAddValue(menu, spin_num, "Joystick 1 - Button 5");\ +SARMenuSpinAddValue(menu, spin_num, "Joystick 1 - Button 6");\ +SARMenuSpinAddValue(menu, spin_num, "Joystick 1 - Button 7");\ +SARMenuSpinAddValue(menu, spin_num, "Joystick 1 - Button 8");\ +SARMenuSpinAddValue(menu, spin_num, "Joystick 1 - Button 9");\ +SARMenuSpinAddValue(menu, spin_num, "Joystick 1 - Button 10");\ +SARMenuSpinAddValue(menu, spin_num, "Joystick 1 - Button 11");\ +SARMenuSpinAddValue(menu, spin_num, "Joystick 1 - Button 12");\ +SARMenuSpinAddValue(menu, spin_num, "Joystick 1 - Button 13");\ +SARMenuSpinAddValue(menu, spin_num, "Joystick 1 - Button 14");\ +SARMenuSpinAddValue(menu, spin_num, "Joystick 1 - Button 15");\ +SARMenuSpinAddValue(menu, spin_num, "Joystick 1 - Button 16");\ +SARMenuSpinAddValue(menu, spin_num, "Joystick 2 - Button 1");\ +SARMenuSpinAddValue(menu, spin_num, "Joystick 2 - Button 2");\ +SARMenuSpinAddValue(menu, spin_num, "Joystick 2 - Button 3");\ +SARMenuSpinAddValue(menu, spin_num, "Joystick 2 - Button 4");\ +SARMenuSpinAddValue(menu, spin_num, "Joystick 2 - Button 5");\ +SARMenuSpinAddValue(menu, spin_num, "Joystick 2 - Button 6");\ +SARMenuSpinAddValue(menu, spin_num, "Joystick 2 - Button 7");\ +SARMenuSpinAddValue(menu, spin_num, "Joystick 2 - Button 8");\ +SARMenuSpinAddValue(menu, spin_num, "Joystick 2 - Button 9");\ +SARMenuSpinAddValue(menu, spin_num, "Joystick 2 - Button 10");\ +SARMenuSpinAddValue(menu, spin_num, "Joystick 2 - Button 11");\ +SARMenuSpinAddValue(menu, spin_num, "Joystick 2 - Button 12");\ +SARMenuSpinAddValue(menu, spin_num, "Joystick 2 - Button 13");\ +SARMenuSpinAddValue(menu, spin_num, "Joystick 2 - Button 14");\ +SARMenuSpinAddValue(menu, spin_num, "Joystick 2 - Button 15");\ +SARMenuSpinAddValue(menu, spin_num, "Joystick 2 - Button 16");\ +SARMenuSpinAddValue(menu, spin_num, "Joystick 3 - Button 1");\ +SARMenuSpinAddValue(menu, spin_num, "Joystick 3 - Button 2");\ +SARMenuSpinAddValue(menu, spin_num, "Joystick 3 - Button 3");\ +SARMenuSpinAddValue(menu, spin_num, "Joystick 3 - Button 4");\ +SARMenuSpinAddValue(menu, spin_num, "Joystick 3 - Button 5");\ +SARMenuSpinAddValue(menu, spin_num, "Joystick 3 - Button 6");\ +SARMenuSpinAddValue(menu, spin_num, "Joystick 3 - Button 7");\ +SARMenuSpinAddValue(menu, spin_num, "Joystick 3 - Button 8");\ +SARMenuSpinAddValue(menu, spin_num, "Joystick 3 - Button 9");\ +SARMenuSpinAddValue(menu, spin_num, "Joystick 3 - Button 10");\ +SARMenuSpinAddValue(menu, spin_num, "Joystick 3 - Button 11");\ +SARMenuSpinAddValue(menu, spin_num, "Joystick 3 - Button 12");\ +SARMenuSpinAddValue(menu, spin_num, "Joystick 3 - Button 13");\ +SARMenuSpinAddValue(menu, spin_num, "Joystick 3 - Button 14");\ +SARMenuSpinAddValue(menu, spin_num, "Joystick 3 - Button 15");\ +SARMenuSpinAddValue(menu, spin_num, "Joystick 3 - Button 16"); + + ypos = 0.20f; + + /* Zoom in button mapping spin */ + spin_num = SARMenuBuildStandardSpin( + core_ptr, menu, XPOS, ypos, MAPPING_SPIN_WIDTH, 0.0f, + "Zoom In ", SAR_MENU_ID_OPT_ZOOM_IN_BUTTON, + SARMenuOptionsSpinCB ); + if(spin_num > -1) + { + spin = SAR_MENU_SPIN(menu->object[spin_num]); + spin->allow_warp = False; + JS_BUTTON_MAPPING_SPIN_VALUES + } - /* Back Button */ - SARMenuBuildStandardButton( - core_ptr, menu, 0.25f, 0.92f, btn_width_std, btn_height_std, - True, + /* Zoom out button mapping spin */ + spin_num = SARMenuBuildStandardSpin( + core_ptr, menu, XPOS, NEXTYPOS, MAPPING_SPIN_WIDTH, 0.0f, + "Zoom Out ", SAR_MENU_ID_OPT_ZOOM_OUT_BUTTON, + SARMenuOptionsSpinCB + ); + if(spin_num > -1) + { + spin = SAR_MENU_SPIN(menu->object[spin_num]); + spin->allow_warp = False; + JS_BUTTON_MAPPING_SPIN_VALUES + } + + /* Hoist up button mapping spin */ + spin_num = SARMenuBuildStandardSpin( + core_ptr, menu, XPOS, NEXTYPOS, MAPPING_SPIN_WIDTH, 0.0f, + "Hoist Up ", SAR_MENU_ID_OPT_HOIST_UP_BUTTON, + SARMenuOptionsSpinCB + ); + if(spin_num > -1) + { + spin = SAR_MENU_SPIN(menu->object[spin_num]); + spin->allow_warp = False; + JS_BUTTON_MAPPING_SPIN_VALUES + } + + /* Hoist down button mapping spin */ + spin_num = SARMenuBuildStandardSpin( + core_ptr, menu, XPOS, NEXTYPOS, MAPPING_SPIN_WIDTH, 0.0f, + "Hoist Down ", SAR_MENU_ID_OPT_HOIST_DOWN_BUTTON, + SARMenuOptionsSpinCB + ); + if(spin_num > -1) + { + spin = SAR_MENU_SPIN(menu->object[spin_num]); + spin->allow_warp = False; + JS_BUTTON_MAPPING_SPIN_VALUES + } + + /* Wheel brake button mapping spin */ + spin_num = SARMenuBuildStandardSpin( + core_ptr, menu, XPOS, NEXTYPOS, MAPPING_SPIN_WIDTH, 0.0f, + "Wheel Brake", SAR_MENU_ID_OPT_WHEEL_BRAKES_BUTTON, + SARMenuOptionsSpinCB + ); + if(spin_num > -1) + { + spin = SAR_MENU_SPIN(menu->object[spin_num]); + spin->allow_warp = False; + JS_BUTTON_MAPPING_SPIN_VALUES + } + + /* Air brake button mapping spin */ + spin_num = SARMenuBuildStandardSpin( + core_ptr, menu, XPOS, NEXTYPOS, MAPPING_SPIN_WIDTH, 0.0f, + "Air Brake ", SAR_MENU_ID_OPT_AIR_BRAKES_BUTTON, + SARMenuOptionsSpinCB + ); + if(spin_num > -1) + { + spin = SAR_MENU_SPIN(menu->object[spin_num]); + spin->allow_warp = False; + JS_BUTTON_MAPPING_SPIN_VALUES + } + + /* Rotate button mapping spin */ + spin_num = SARMenuBuildStandardSpin( + core_ptr, menu, XPOS, NEXTYPOS, MAPPING_SPIN_WIDTH, 0.0f, + "Rotate* ", SAR_MENU_ID_OPT_ROTATE_BUTTON, + SARMenuOptionsSpinCB + ); + if(spin_num > -1) + { + spin = SAR_MENU_SPIN(menu->object[spin_num]); + spin->allow_warp = False; + JS_BUTTON_MAPPING_SPIN_VALUES + } +#undef MAPPING_MAPPING_SPIN_WIDTH +#undef JS_BUTTON_MAPPING_SPIN_VALUES + + /* Rotate button help label */ + label_num = SARMenuLabelNew( + menu, XPOS, NEXTYPOS - 0.013, 0, 0, #if defined(PROG_LANGUAGE_SPANISH) -"Espalda" +"* Trata el banco con el eje de rumbo. " #elif defined(PROG_LANGUAGE_FRENCH) -"Dos" +"* Traite le roulis en tant que lacet. " #elif defined(PROG_LANGUAGE_GERMAN) -"Zurück" +"* Behandelt die Querneigung zur \n\ + Kursachse." #elif defined(PROG_LANGUAGE_ITALIAN) -"Dorso" +"* Considera la sponda rispetto all \n\ + all asse della rotta." #elif defined(PROG_LANGUAGE_DUTCH) -"Rug" +"* Behandelt de oever naar de koersas. " #elif defined(PROG_LANGUAGE_PORTUGUESE) -"Costas" +"* Trata a margem como eixo de direção." #elif defined(PROG_LANGUAGE_NORWEGIAN) -"Frem" +"* Behandler bank til kursakse. " #else -"Back" +"* Treats bank to heading axis. " #endif - , SAR_MENU_ID_GOTO_OPTIONS_CONTROLLER + , &label_color, font, + NULL /* No background image */ ); + if(label_num > -1) + { + sar_menu_label_struct *label = SAR_MENU_LABEL( + menu->object[label_num] + ); + label->align = SAR_MENU_LABEL_ALIGN_LEFT; + } +#undef NEXTYPOS +#undef LASTYPOS +#undef XPOS +#undef MAPPING_SPIN_WIDTH +#define XPOS 0.63f +#define YPOS 0.76f - /* ****************************************************** */ - /* Menu: Options->Controller->Test */ - img_path = SARMenuBuildGetFullPath(SAR_DEF_MENU_BGIMG_STANDARD_FILE); - menu = SARMenuNew( - SAR_MENU_TYPE_STANDARD, - SAR_MENU_NAME_OPTIONS_CONTROLLER_TEST, - img_path + /* Clear Js# Mapping label */ + label_num = SARMenuLabelNew( + menu, XPOS, YPOS, 0, 0, +#if defined(PROG_LANGUAGE_SPANISH) +" Borrar Js# Mapping " +#elif defined(PROG_LANGUAGE_FRENCH) +" Efface Js# Mapping " +#elif defined(PROG_LANGUAGE_GERMAN) +" Loschen Js# Mapping " +#elif defined(PROG_LANGUAGE_ITALIAN) +" Cancella Js# Mapping" +#elif defined(PROG_LANGUAGE_DUTCH) +"Verwijder Js# Mapping" +#elif defined(PROG_LANGUAGE_PORTUGUESE) +" Apagar Js# Mapping " +#elif defined(PROG_LANGUAGE_NORWEGIAN) +" Slett Js# Mapping " +#else +" Clear Js# Mapping " +#endif + , &label_color, font, + NULL /* No background image */ + ); + if(label_num > -1) + { + sar_menu_label_struct *label = SAR_MENU_LABEL( + menu->object[label_num] + ); + label->align = SAR_MENU_LABEL_ALIGN_LEFT; + } +#undef XPOS +#define XPOS 0.63f + 0.166f +#define BTN_WIDTH 50 + /* Joystick 0 Mappings Reset Button */ + SARMenuBuildStandardButton( + core_ptr, menu, XPOS, YPOS, BTN_WIDTH, btn_height_std, + True, + "1", + SAR_MENU_ID_RESET_CONTROLLER_JS0_MAPPING ); - if(menu == NULL) - return(-1); - else - SARBuildMenusAddToList(core_ptr, menu); - menu->always_full_redraw = opt->menu_always_full_redraw; - /* Joystick Output Display */ - SARMenuMDisplayNew( - menu, 0.50f, 0.36f, 0.95f, 0.60f, - (const sar_image_struct **)core_ptr->menu_list_bg_img, - core_ptr, SAR_MENU_ID_OPT_JS_TEST_UPDATE, - SARMenuOptionsJoystickTestDrawCB +#undef XPOS +#define XPOS 0.63f + 0.165f + 0.07f + /* Joystick 1 Mappings Reset Button */ + SARMenuBuildStandardButton( + core_ptr, menu, XPOS, YPOS, BTN_WIDTH, btn_height_std, + True, + "2", + SAR_MENU_ID_RESET_CONTROLLER_JS1_MAPPING ); - /* Refresh Controllers Button */ - SARMenuBuildOptionsButton( - core_ptr, menu, 0.25f, 0.74f, btn_width_std, btn_height_std, - True, "Refresh", SAR_MENU_ID_OPT_CONTROLLER_REFRESH +#undef XPOS +#define XPOS 0.63f + 0.165f + 2 * 0.07f + /* Joystick 2 Mappings Reset Button */ + SARMenuBuildStandardButton( + core_ptr, menu, XPOS, YPOS, BTN_WIDTH, btn_height_std, + True, + "3", + SAR_MENU_ID_RESET_CONTROLLER_JS2_MAPPING ); +#undef YPOS +#undef BTN_WIDTH /* Back Button */ SARMenuBuildStandardButton( @@ -2668,7 +3158,7 @@ to set button number" #if defined(PROG_LANGUAGE_SPANISH) "Espalda" #elif defined(PROG_LANGUAGE_FRENCH) -"Dos" +"Retour" #elif defined(PROG_LANGUAGE_GERMAN) "Zurück" #elif defined(PROG_LANGUAGE_ITALIAN) @@ -2682,7 +3172,7 @@ to set button number" #else "Back" #endif - , SAR_MENU_ID_GOTO_OPTIONS_CONTROLLER + , SAR_MENU_ID_GOTO_OPTIONS_CONTROLLER_JOYSTICK ); diff --git a/src/sarmenucb.c b/src/sarmenucb.c index cdae01c..97fa181 100644 --- a/src/sarmenucb.c +++ b/src/sarmenucb.c @@ -76,7 +76,7 @@ void SARMenuSpinCB( #define STRDUP(s) (((s) != NULL) ? strdup(s) : NULL) #define STRLEN(s) (((s) != NULL) ? ((int)strlen(s)) : 0) -#define ISSTREMPTY(s) (((s) != NULL) ? ((s) == '\0') : True) +#define ISSTREMPTY(s) (((s) != NULL) ? ((*s) == '\0') : True) /* @@ -1071,18 +1071,44 @@ free flight." break; case SAR_MENU_ID_GOTO_OPTIONS_CONTROLLER: + /* Is actual menu the joystick test menu? */ + if(core_ptr->cur_menu == SARMatchMenuByName(core_ptr, SAR_MENU_NAME_OPTIONS_CONTROLLER_JOYSTICK)){ + /* Shut off joystick events because we needed them only for + * joystick hot plug detection in joystick test menu. + */ + SDL_JoystickEventState(SDL_IGNORE); + } SARMenuSwitchToMenu(core_ptr, SAR_MENU_NAME_OPTIONS_CONTROLLER); break; - case SAR_MENU_ID_GOTO_OPTIONS_CONTROLLER_JS_BTN: + + case SAR_MENU_ID_GOTO_OPTIONS_CONTROLLER_JOYSTICK: + /* Is actual menu the joystick mapping menu? */ + if(core_ptr->cur_menu == SARMatchMenuByName(core_ptr, SAR_MENU_NAME_OPTIONS_CONTROLLER_JS_MAPPING)){ + SARMenuOptionsJoystickMappingExit(core_ptr); + } + SARMenuOptionsJoystickReinit(core_ptr); SARMenuSwitchToMenu( - core_ptr, SAR_MENU_NAME_OPTIONS_CONTROLLER_JS_BTN - ); + core_ptr, SAR_MENU_NAME_OPTIONS_CONTROLLER_JOYSTICK + ); break; - case SAR_MENU_ID_GOTO_OPTIONS_CONTROLLER_TEST: + case SAR_MENU_ID_GOTO_OPTIONS_CONTROLLER_JS_MAPPING: + /* Is actual menu the joystick test menu? */ + if(core_ptr->cur_menu == SARMatchMenuByName(core_ptr, SAR_MENU_NAME_OPTIONS_CONTROLLER_JOYSTICK)){ + SARMenuOptionsJoystickMappingPrepare(core_ptr); + } SARMenuSwitchToMenu( - core_ptr, SAR_MENU_NAME_OPTIONS_CONTROLLER_TEST + core_ptr, SAR_MENU_NAME_OPTIONS_CONTROLLER_JS_MAPPING ); break; + case SAR_MENU_ID_RESET_CONTROLLER_JS0_MAPPING: + SARMenuOptionsJoystickMappingReset(core_ptr, 1<<0); + break; + case SAR_MENU_ID_RESET_CONTROLLER_JS1_MAPPING: + SARMenuOptionsJoystickMappingReset(core_ptr, 1<<1); + break; + case SAR_MENU_ID_RESET_CONTROLLER_JS2_MAPPING: + SARMenuOptionsJoystickMappingReset(core_ptr, 1<<2); + break; case SAR_MENU_ID_GOTO_OPTIONS_GRAPHICS: SARMenuSwitchToMenu(core_ptr, SAR_MENU_NAME_OPTIONS_GRAPHICS); diff --git a/src/sarmenucodes.h b/src/sarmenucodes.h index 58c6387..8194f2c 100644 --- a/src/sarmenucodes.h +++ b/src/sarmenucodes.h @@ -46,8 +46,9 @@ #define SAR_MENU_NAME_OPTIONS "Options" #define SAR_MENU_NAME_OPTIONS_SIMULATION "Options Simulation" #define SAR_MENU_NAME_OPTIONS_CONTROLLER "Options Controler" -#define SAR_MENU_NAME_OPTIONS_CONTROLLER_JS_BTN "Options Controler JS Buttons" -#define SAR_MENU_NAME_OPTIONS_CONTROLLER_TEST "Options Controler Test" +#define SAR_MENU_NAME_OPTIONS_CONTROLLER_JOYSTICK "Options Controler Joystick" +#define SAR_MENU_NAME_OPTIONS_CONTROLLER_JS_MAPPING "Options Controller JS Mapping" +#define SAR_MENU_NAME_OPTIONS_CONTROLLER_KB_MAPPING "Options Controller KB Mapping" #define SAR_MENU_NAME_OPTIONS_GRAPHICS "Options Graphics" #define SAR_MENU_NAME_OPTIONS_GRAPHICS_INFO "Options Graphics Info" #define SAR_MENU_NAME_OPTIONS_SOUND "Options Sound" @@ -110,8 +111,12 @@ #define SAR_MENU_ID_GOTO_OPTIONS_SIMULATION 100 #define SAR_MENU_ID_GOTO_OPTIONS_CONTROLLER 110 -#define SAR_MENU_ID_GOTO_OPTIONS_CONTROLLER_JS_BTN 111 -#define SAR_MENU_ID_GOTO_OPTIONS_CONTROLLER_TEST 112 +#define SAR_MENU_ID_GOTO_OPTIONS_CONTROLLER_JOYSTICK 111 +#define SAR_MENU_ID_GOTO_OPTIONS_CONTROLLER_JS_MAPPING 112 +#define SAR_MENU_ID_RESET_CONTROLLER_JS0_MAPPING 113 +#define SAR_MENU_ID_RESET_CONTROLLER_JS1_MAPPING 114 +#define SAR_MENU_ID_RESET_CONTROLLER_JS2_MAPPING 115 +#define SAR_MENU_ID_GOTO_OPTIONS_CONTROLLER_KB_MAPPING 116 #define SAR_MENU_ID_GOTO_OPTIONS_GRAPHICS 120 #define SAR_MENU_ID_GOTO_OPTIONS_GRAPHICS_INFO 121 #define SAR_MENU_ID_GRAPHICS_INFO_MESG 122 @@ -128,16 +133,34 @@ #define SAR_MENU_ID_OPT_DAMAGE_RESISTANCE 512 /* Spin */ #define SAR_MENU_ID_OPT_FLIGHT_PHYSICS 513 /* Spin */ -/* 520, 521 and 524 corresponded to deleted types but could be re-used */ -#define SAR_MENU_ID_OPT_JS0_AXISES 522 /* Spin */ -#define SAR_MENU_ID_OPT_JS1_AXISES 523 /* Spin */ -#define SAR_MENU_ID_OPT_JS0_BUTTON_ACTION 530 /* Spin */ -#define SAR_MENU_ID_OPT_JS0_BUTTON_NUMBER 531 /* Spin */ -#define SAR_MENU_ID_OPT_JS1_BUTTON_ACTION 532 /* Spin */ -#define SAR_MENU_ID_OPT_JS1_BUTTON_NUMBER 533 /* Spin */ -#define SAR_MENU_ID_OPT_CONTROLLER_REFRESH 534 /* Button */ +#define SAR_MENU_ID_OPT_HEADING_AXIS 520 /* Spin */ +#define SAR_MENU_ID_OPT_HEADING_AXIS_INV 620 /* Switch */ +#define SAR_MENU_ID_OPT_PITCH_AXIS 521 /* Spin */ +#define SAR_MENU_ID_OPT_PITCH_AXIS_INV 621 /* Switch */ +#define SAR_MENU_ID_OPT_BANK_AXIS 522 /* Spin */ +#define SAR_MENU_ID_OPT_BANK_AXIS_INV 622 /* Switch */ +#define SAR_MENU_ID_OPT_THROTTLE_AXIS 523 /* Spin */ +#define SAR_MENU_ID_OPT_THROTTLE_AXIS_INV 623 /* Switch */ +#define SAR_MENU_ID_OPT_BRAKE_LEFT_AXIS 524 /* Spin */ +#define SAR_MENU_ID_OPT_BRAKE_LEFT_AXIS_INV 624 /* Switch */ +#define SAR_MENU_ID_OPT_BRAKE_RIGHT_AXIS 525 /* Spin */ +#define SAR_MENU_ID_OPT_BRAKE_RIGHT_AXIS_INV 625 /* Switch */ +#define SAR_MENU_ID_OPT_POV_HAT 526 /* Spin */ +#define SAR_MENU_ID_OPT_POV_HAT_INV 626 /* Switch */ +#define SAR_MENU_ID_OPT_POV_HAT_X 527 /* Spin */ +#define SAR_MENU_ID_OPT_POV_HAT_X_INV 627 /* Switch */ +#define SAR_MENU_ID_OPT_POV_HAT_Y 528 /* Spin */ +#define SAR_MENU_ID_OPT_POV_HAT_Y_INV 628 /* Switch */ #define SAR_MENU_ID_OPT_JS_TEST_UPDATE 535 /* MDisplay */ +#define SAR_MENU_ID_OPT_ROTATE_BUTTON 540 /* Spin */ +#define SAR_MENU_ID_OPT_AIR_BRAKES_BUTTON 541 /* Spin */ +#define SAR_MENU_ID_OPT_WHEEL_BRAKES_BUTTON 542 /* Spin */ +#define SAR_MENU_ID_OPT_ZOOM_IN_BUTTON 543 /* Spin */ +#define SAR_MENU_ID_OPT_ZOOM_OUT_BUTTON 544 /* Spin */ +#define SAR_MENU_ID_OPT_HOIST_UP_BUTTON 545 /* Spin */ +#define SAR_MENU_ID_OPT_HOIST_DOWN_BUTTON 546 /* Spin */ + #define SAR_MENU_ID_OPT_GROUND_TEXTURE 550 /* Switch */ #define SAR_MENU_ID_OPT_OBJECT_TEXTURE 551 /* Switch */ #define SAR_MENU_ID_OPT_CLOUDS 552 /* Switch */ diff --git a/src/sarmenumanage.c b/src/sarmenumanage.c index 7d22a4c..3014c79 100644 --- a/src/sarmenumanage.c +++ b/src/sarmenumanage.c @@ -33,11 +33,11 @@ #define SAR_MENU_MANAGE_PROTOTYPE \ sar_core_struct *core_ptr, sar_menu_struct *menu -static void SARMenuManageOptionsControllerJSButtons( +static void SARMenuManageOptionsControllerJSMapping( SAR_MENU_MANAGE_PROTOTYPE ); -static void SARMenuManageOptionsControllerTest( +static void SARMenuManageOptionsControllerJoystick( SAR_MENU_MANAGE_PROTOTYPE ); @@ -55,125 +55,474 @@ void SARMenuManage( #define MIN(a,b) (((a) < (b)) ? (a) : (b)) #define CLIP(a,l,h) (MIN(MAX((a),(l)),(h))) +#define DO_REDRAW_OBJECT(d,m,n) { \ + if((m)->always_full_redraw) \ + SARMenuDrawAll((d), (m)); \ + else \ + SARMenuDrawObject((d),(m),(n)); \ + GWSwapBuffer(d); \ +} + /* - * Manages menu Options->Controller->Buttons + * Manages menu Options->Controller->Joystick->Mapping + * + * 1) Selects a spin index by moving an axis or clicking on a button. + * Corresponding opt->js*_* value is set by SARMenuOptionsSpinCB(). + * + * 2) Copy moved/clicked joystick SDL GUID string and name + * to opt->js*_sdl_guid_s and opt->js*_sdl_name. */ -static void SARMenuManageOptionsControllerJSButtons( +static void SARMenuManageOptionsControllerJSMapping( SAR_MENU_MANAGE_PROTOTYPE ) { +//fprintf(stderr, "%s:%d : Entering SARMenuManageOptionsControllerJSMapping()\n", __FILE__, __LINE__); +#define FG_COLOR_WHITE sar_menu_color_struct fg_color = { 1.0, 0.9, 0.9, 0.9 }; // ( a, r, g, b ) +#define FG_COLOR_YELLOW sar_menu_color_struct fg_color = { 1.0, 0.9, 0.9, 0.0 }; // ( a, r, g, b ) gw_display_struct *display = core_ptr->display; gctl_struct *gc = core_ptr->gctl; - int jsnum; - int js0_btn_num_spin_num, js1_btn_num_spin_num; -/* - sar_menu_spin_struct *js0_btn_role_spin = SARMenuGetSpin( - menu, 0, NULL + gctl_js_mapping_menu_data_struct *axis; + sar_option_struct *opt = &core_ptr->option; + int jsnum, i, device_index, activated = 0; + SDL_Joystick *sdl_joystick = NULL; + Sint16 axis_value; + Boolean is_an_axis_spin = False, is_the_pov_hat_spin = False, is_a_button_spin = False; + sar_menu_label_struct *label_ptr; + char guid_str[33]; + SDL_JoystickGUID guid; + + + GctlJsOpenAndMapp(gc, NULL); + SDL_JoystickUpdate(); + + sar_menu_spin_struct *spin = SAR_MENU_SPIN( + SARMenuGetObject(menu, menu->selected_object) ); - */ - sar_menu_spin_struct *js0_btn_num_spin = SARMenuGetSpin( - menu, 1, &js0_btn_num_spin_num - ); -/* - sar_menu_spin_struct *js1_btn_role_spin = SARMenuGetSpin( - menu, 2, NULL - ); - */ - sar_menu_spin_struct *js1_btn_num_spin = SARMenuGetSpin( - menu, 3, &js1_btn_num_spin_num - ); - /* Game controller not set to joystick? */ - if((gc != NULL) ? !(gc->controllers & GCTL_CONTROLLER_JOYSTICK) : True) + + /* Get spin type */ + + switch(spin->id){ + case SAR_MENU_ID_OPT_HEADING_AXIS: + case SAR_MENU_ID_OPT_PITCH_AXIS: + case SAR_MENU_ID_OPT_BANK_AXIS: + case SAR_MENU_ID_OPT_THROTTLE_AXIS: + case SAR_MENU_ID_OPT_BRAKE_LEFT_AXIS: + case SAR_MENU_ID_OPT_BRAKE_RIGHT_AXIS: + case SAR_MENU_ID_OPT_POV_HAT_X: + case SAR_MENU_ID_OPT_POV_HAT_Y: + is_an_axis_spin = True; + break; + + case SAR_MENU_ID_OPT_POV_HAT: + is_the_pov_hat_spin = True; + break; + + case SAR_MENU_ID_OPT_ROTATE_BUTTON: + case SAR_MENU_ID_OPT_AIR_BRAKES_BUTTON: + case SAR_MENU_ID_OPT_WHEEL_BRAKES_BUTTON: + case SAR_MENU_ID_OPT_ZOOM_IN_BUTTON: + case SAR_MENU_ID_OPT_ZOOM_OUT_BUTTON: + case SAR_MENU_ID_OPT_HOIST_UP_BUTTON: + case SAR_MENU_ID_OPT_HOIST_DOWN_BUTTON: + is_a_button_spin = True; + break; + + default: + break; + } + + /* Change "help labels" color and text as needed. + * Because labels don't have any ID, label detection is made with + * label label (i.e. label text). Only the 3 first characters are + * used for this detection in order to allow text translation. + * + * Note that labels are always center aligned thus text width and + * number of text lines are important. + */ + + /* Selected object not a spin? */ + if(!SAR_MENU_IS_SPIN(spin)){ + for(i = 0; i < menu->total_objects; i++){ + label_ptr = SARMenuGetObject(menu, i); + + /* This object not the good one? */ + if(label_ptr == NULL || + label_ptr->type != SAR_MENU_OBJECT_TYPE_LABEL || + !strstr(label_ptr->label, "1) ") + ) + continue; + + FG_COLOR_YELLOW + + /* Set label color */ + SARMenuLabelSetLabel(display, menu, i, NULL, &fg_color, True); + + break; + } + for(i = 0; i < menu->total_objects; i++){ + label_ptr = SARMenuGetObject(menu, i); + + /* This object not the good one? */ + if(label_ptr == NULL || + label_ptr->type != SAR_MENU_OBJECT_TYPE_LABEL || + !strstr(label_ptr->label, "2) ") + ) + continue; + + FG_COLOR_WHITE + + /* Set label text and color */ + SARMenuLabelSetLabel(display, menu, i, +#if defined(PROG_LANGUAGE_SPANISH) +"2) Nuevas instrucciones vienen... \n\ + \n\ + " +#elif defined(PROG_LANGUAGE_FRENCH) +"2) De nouvelles instructions arrivent... \n\ + \n\ + " +#elif defined(PROG_LANGUAGE_GERMAN) +"2) Neue Anweisungen kommen... \n\ + \n\ + " +#elif defined(PROG_LANGUAGE_ITALIAN) +"2) Nuove istruzioni in arrivo... \n\ + \n\ + " +#elif defined(PROG_LANGUAGE_DUTCH) +"2) Er komen nieuwe instructies... \n\ + \n\ + " +#elif defined(PROG_LANGUAGE_PORTUGUESE) +"2) Novas instrucoes a chegar... \n\ + \n\ + " +#elif defined(PROG_LANGUAGE_NORWEGIAN) +"2) Nye instruksjoner kommer... \n\ + \n\ + " +#else +"2) New instructions coming... \n\ + \n\ + " +#endif + , &fg_color, True + ); + + break; + } return; + } + /* Selected object is a spin */ + else{ + for(i = 0; i < menu->total_objects; i++){ + label_ptr = SARMenuGetObject(menu, i); - /* Joystick #0. */ - jsnum = 0; - if((js0_btn_num_spin != NULL) && (gc->total_joysticks > jsnum)) - { - SDL_Joystick *sdljoystick = gc->sdljoystick[0]; - int i,button = -1; - sar_menu_spin_struct *spin = js0_btn_num_spin; - - /* This joystick initialized? */ - if (sdljoystick == NULL && SDL_NumJoysticks()){ - sdljoystick = SDL_JoystickOpen(jsnum); - } - if (sdljoystick != NULL){ - - /* Look for a currently pressed button. */ - for(i = 0; i < SDL_JoystickNumButtons(sdljoystick); i++) - { - if(SDL_JoystickGetButton(sdljoystick,i)) - { - button = i; - break; - } - } - } - - /* Was a button pressed? */ - if(button > -1) - { - /* Spin button values start at index 1 so button 0 - * is spin value index 1. - */ - i = button + 1; - /* Change in value? */ - if(spin->cur_value != i) - SARMenuSpinSelectValueIndex( - display, menu, js0_btn_num_spin_num, - i, True + /* This object not the good one? */ + if(label_ptr == NULL || + label_ptr->type != SAR_MENU_OBJECT_TYPE_LABEL || + !strstr(label_ptr->label, "1) ") + ) + continue; + + FG_COLOR_WHITE + + /* Set label color */ + SARMenuLabelSetLabel(display, menu, i, NULL, &fg_color, True); + + break; + } + for(i = 0; i < menu->total_objects; i++){ + label_ptr = SARMenuGetObject(menu, i); + + /* This object not the good one? */ + if(label_ptr == NULL || + label_ptr->type != SAR_MENU_OBJECT_TYPE_LABEL || + !strstr(label_ptr->label, "2) ") + ) + continue; + + FG_COLOR_YELLOW + + /* Set label text (handled by spin role type) and color */ + + if(is_an_axis_spin) + SARMenuLabelSetLabel(display, menu, i, +#if defined(PROG_LANGUAGE_SPANISH) +"2) Mueva el eje de un joystick de punta a punta para seleccionarlo, \n\ + o presione la tecla 'Inicio' del teclado para restablecer la asignacion \n\ + del cuadro de funciones. " +#elif defined(PROG_LANGUAGE_FRENCH) +"2) Bougez un axe de joystick de butee en butee pour le selectionner, \n\ + ou appuyez sur la touche 'Debut' du clavier pour deselectionner ce role. \n\ + " +#elif defined(PROG_LANGUAGE_GERMAN) +"2) Bewegen Sie eine Joystickachse von Zehe zu Zehe, um sie auszuwahlen, \n\ + oder drucken Sie die Home-Taste auf der Tastatur, um die \n\ + Rollenfeldzuordnung zuruckzusetzen. " +#elif defined(PROG_LANGUAGE_ITALIAN) +"2) Muovi l'asse del joystick da un piede all'altro per selezionarlo, \n\ + oppure premere il tasto 'Home' della tastiera per reimpostare la \n\ + mappatura delle caselle dei ruoli. " +#elif defined(PROG_LANGUAGE_DUTCH) +"2) Beweeg de as van een joystick van teen tot teen om deze te selecteren, \n\ + of druk op de 'Home'-toets op het toetsenbord om de rolboxtoewijzing \n\ + opnieuw in te stellen. " +#elif defined(PROG_LANGUAGE_PORTUGUESE) +"2) Mova o eixo do joystick de ponta a ponta para o seleccionar, \n\ + ou prima a tecla 'Home' do teclado para repor o mapeamento da caixa de \n\ + funcoes. " +#elif defined(PROG_LANGUAGE_NORWEGIAN) +"2) Flytt en joystick-akse fra ta til ta for a velge den, \n\ + eller trykk pa 'Hjem'-tasten pa tastaturet for a tilbakestille \n\ + rollebokskartlegging. " +#else +"2) Move a joystick axis from toe to toe to select it, \n\ + or press keyboard 'Home' key to reset role box mapping. \n\ + " +#endif + , &fg_color, True + ); + + else if(is_the_pov_hat_spin) + SARMenuLabelSetLabel(display, menu, i, +#if defined(PROG_LANGUAGE_SPANISH) +"Haga clic en un cuadro de funcion y luego mueva el eje del joystick \n\ + hacia la punta para establecer la funcion del eje o presione un \n\ + boton del joystick para configurar la funcion del boton. " +#elif defined(PROG_LANGUAGE_FRENCH) +"2) Bougez un bouton de point de vue d'un joystick pour le selectionner, \n\ + ou appuyez sur la touche 'Debut' du clavier pour deselectionner ce role. \n\ + " +#elif defined(PROG_LANGUAGE_GERMAN) +"Klicken Sie auf ein Rollenfeld und bewegen Sie dann die \n\ + Joystick-Achse nach vorne, um die Achsenrolle festzulegen oder \n\ + druecken Sie eine Joystick-Taste, um die Tastenrolle festzulegen. " +#elif defined(PROG_LANGUAGE_ITALIAN) +"Fare clic su una casella di ruolo, quindi spostare l'asse del \n\ + joystick in punta per impostare il ruolo dell'asse oppure premere un \n\ + pulsante del joystick per impostare il ruolo del pulsante. " +#elif defined(PROG_LANGUAGE_DUTCH) +"Klik op een rolvak en beweeg de as van de joystick naar de teen om \n\ + de rol van de as in te stellen of druk op een joystickknop om de \n\ + rol van de knop in te stellen. " +#elif defined(PROG_LANGUAGE_PORTUGUESE) +"Clique em uma caixa de funcao e mova o eixo do joystick para a ponta \n\ + do pe para definir a funcao do eixo ou pressione um botao do \n\ + joystick para definir a funcao do botao. " +#elif defined(PROG_LANGUAGE_NORWEGIAN) +"Klikk pa en rolleboks og flytt styrespakens akse til ta for a angi \n\ + akserolle eller trykk pa en styrespakknapp for a angi knapprolle. \n\ + " +#else +"2) Move a joystick POV hat to select it, \n\ + or press keyboard 'Home' key to reset role box mapping. \n\ + " +#endif + , &fg_color, True ); - } - } - /* Joystick #1. */ - jsnum = 1; - if((js1_btn_num_spin != NULL) && (gc->total_joysticks > jsnum)) - { - SDL_Joystick *sdljoystick = gc->sdljoystick[1]; - int i,button = -1; - sar_menu_spin_struct *spin = js0_btn_num_spin; - - /* This joystick initialized? */ - if (sdljoystick == NULL && SDL_NumJoysticks()){ - sdljoystick = SDL_JoystickOpen(jsnum); - } - if (sdljoystick != NULL){ - - /* Look for a currently pressed button. */ - for(i = 0; i < SDL_JoystickNumButtons(sdljoystick); i++) - { - if(SDL_JoystickGetButton(sdljoystick,i)) - { - button = i; - break; - } - } - } - - /* Was a button pressed? */ - if(button > -1) - { - /* Spin button values start at index 1 so button 0 - * is spin value index 1. - */ - i = button + 1; - /* Change in value? */ - if(spin->cur_value != i) - SARMenuSpinSelectValueIndex( - display, menu, js1_btn_num_spin_num, - i, True + else if(is_a_button_spin) + SARMenuLabelSetLabel(display, menu, i, +#if defined(PROG_LANGUAGE_SPANISH) +"Haga clic en un cuadro de funcion y luego mueva el eje del joystick \n\ + hacia la punta para establecer la funcion del eje o presione un \n\ + botón del joystick para configurar la funcion del boton. " +#elif defined(PROG_LANGUAGE_FRENCH) +"2) Appuyez sur un bouton d'un joystick pour le selectionner, \n\ + ou appuyez sur la touche 'Debut' du clavier pour deselectionner ce role. \n\ + " +#elif defined(PROG_LANGUAGE_GERMAN) +"Klicken Sie auf ein Rollenfeld und bewegen Sie dann die \n\ + Joystick-Achse nach vorne, um die Achsenrolle festzulegen oder \n\ + drücken Sie eine Joystick-Taste, um die Tastenrolle festzulegen. " +#elif defined(PROG_LANGUAGE_ITALIAN) +"Fare clic su una casella di ruolo, quindi spostare l'asse del \n\ + joystick in punta per impostare il ruolo dell'asse oppure premere un \n\ + pulsante del joystick per impostare il ruolo del pulsante. " +#elif defined(PROG_LANGUAGE_DUTCH) +"Klik op een rolvak en beweeg de as van de joystick naar de teen om \n\ + de rol van de as in te stellen of druk op een joystickknop om de \n\ + rol van de knop in te stellen. " +#elif defined(PROG_LANGUAGE_PORTUGUESE) +"Clique em uma caixa de funcao e mova o eixo do joystick para a ponta \n\ + do pe para definir a funcao do eixo ou pressione um botao do \n\ + joystick para definir a funcao do botao. " +#elif defined(PROG_LANGUAGE_NORWEGIAN) +"Klikk pa en rolleboks og flytt styrespakens akse til ta for a angi \n\ + akserolle eller trykk pa en styrespakknapp for a angi knapprolle. \n\ + " +#else +"2) Press a joystick button to select it, \n\ + or press keyboard 'Home' key to reset role box mapping. \n\ + " +#endif + , &fg_color, True ); - } + + break; + } + } + + /* Set spin value */ + + for(jsnum = 0; jsnum < gc->total_sdl_joysticks; jsnum++){ + sdl_joystick = gc->sdljoystick[jsnum]; + + if(sdl_joystick == NULL) + continue; + + if(is_an_axis_spin){ + /* Look for a currently moved axis. */ + for(i = 0; i < SDL_JoystickNumAxes(sdl_joystick); i++) + { + if(i >= MAX_JOYSTICK_AXES) + break; + + axis_value = SDL_JoystickGetAxis(sdl_joystick, i); + axis = &gc->js_mapping_axes_values[jsnum * MAX_JOYSTICK_AXES + i]; + + if(axis_value < 0 && axis_value < axis->min) + axis->min = axis_value; + if(axis_value > 0 && axis_value > axis->max) + axis->max = axis_value; + + if((int)axis->max - (int)axis->min > 49151) + { + /* Axis widely moved, set spin index to match player + * choice. + */ + SARMenuSpinSelectValueIndex( + display, menu, menu->selected_object, + (jsnum * MAX_JOYSTICK_AXES + i) + 1, True + ); + + /* Mark this joystick as activated */ + activated |= 1 << jsnum; + + /* To go out of 'for(jsnum' loop */ + jsnum = gc->total_sdl_joysticks; + + /* Go out of 'for(i' loop */ + break; + } + } + } + else if(is_the_pov_hat_spin){ + for(i = 0; i < SDL_JoystickNumHats(sdl_joystick); i++){ + if(i >= MAX_JOYSTICK_HATS) + break; + + /* Hat not centered (thus moved)? */ + if(SDL_JoystickGetHat(sdl_joystick, i) != SDL_HAT_CENTERED){ + /* Set spin index to match player choice */ + SARMenuSpinSelectValueIndex( + display, menu, menu->selected_object, + (jsnum * MAX_JOYSTICK_HATS + i) + 1, True + ); + + /* Mark this joystick as activated */ + activated |= 1 << jsnum; + + /* To go out of 'for(jsnum' loop */ + jsnum = gc->total_sdl_joysticks; + + /* Go out of 'for(i' loop */ + break; + } + } + } + else if(is_a_button_spin){ + for(i = 0; i < SDL_JoystickNumButtons(sdl_joystick); i++){ + if(i >= MAX_JOYSTICK_BTNS) + break; + + /* Button pressed? */ + if(SDL_JoystickGetButton(sdl_joystick, i)){ + /* Set spin index to match player choice */ + SARMenuSpinSelectValueIndex( + display, menu, menu->selected_object, + (jsnum * MAX_JOYSTICK_BTNS + i) + 1, True + ); + + /* Mark this joystick as activated */ + activated |= 1 << jsnum; + + /* To go out of 'for(jsnum' loop */ + jsnum = gc->total_sdl_joysticks; + + /* Go out of 'for(i' loop */ + break; + } + } + } + } + + /* Copy sdl joystick(s) guid string to core options: this will + * signal that this joystick is mapped to at least one role. + */ + + i = 0; + if(activated & 1<< i && strlen(opt->js0_sdl_guid_s) == 0){ + + device_index = GetSdlJsIndexFromGcSdlJoystick(gc, i); + if(device_index > -1){ + guid = SDL_JoystickGetDeviceGUID(device_index); + SDL_JoystickGetGUIDString(guid, guid_str, sizeof(guid_str)); + strcpy(opt->js0_sdl_guid_s, guid_str); + + if(opt->js0_sdl_name != NULL) + free(opt->js0_sdl_name); + opt->js0_sdl_name = STRDUP(SDL_JoystickNameForIndex(device_index)); + } + } + i = 1; + if(activated & 1<< i && strlen(opt->js1_sdl_guid_s) == 0){ + device_index = GetSdlJsIndexFromGcSdlJoystick(gc, i); + if(device_index > -1){ + guid = SDL_JoystickGetDeviceGUID(device_index); + SDL_JoystickGetGUIDString(guid, guid_str, sizeof(guid_str)); + strcpy(opt->js1_sdl_guid_s, guid_str); + + if(opt->js1_sdl_name != NULL) + free(opt->js1_sdl_name); + opt->js1_sdl_name = STRDUP(SDL_JoystickNameForIndex(device_index)); + } + } + i = 2; + if(activated & 1<< i && strlen(opt->js2_sdl_guid_s) == 0){ + device_index = GetSdlJsIndexFromGcSdlJoystick(gc, i); + if(device_index > -1){ + guid = SDL_JoystickGetDeviceGUID(device_index); + SDL_JoystickGetGUIDString(guid, guid_str, sizeof(guid_str)); + strcpy(opt->js2_sdl_guid_s, guid_str); + + if(opt->js2_sdl_name != NULL) + free(opt->js2_sdl_name); + opt->js2_sdl_name = STRDUP(SDL_JoystickNameForIndex(device_index)); + } + } + + if(activated != 0 && is_an_axis_spin){ + /* Clear min and max values of all axes */ + + for(jsnum = 0; jsnum < gc->total_sdl_joysticks; jsnum++){ + for(i = 0; i < MAX_JOYSTICK_AXES; i++){ + axis = &gc->js_mapping_axes_values[jsnum * MAX_JOYSTICK_AXES + i]; + axis->min = 0; + axis->max = 0; + } + } } + +//fprintf(stderr, "%s:%d : Exiting SARMenuManageOptionsControllerJSMapping()\n", __FILE__, __LINE__); } /* - * Manages menu Options->Controller->Test + * Manages menu Options->Controller->Joystick */ -static void SARMenuManageOptionsControllerTest( +static void SARMenuManageOptionsControllerJoystick( SAR_MENU_MANAGE_PROTOTYPE ) { @@ -185,10 +534,6 @@ static void SARMenuManageOptionsControllerTest( if((display == NULL) || (gc == NULL)) return; - /* No joysticks? */ - if(gc->total_joysticks <= 0) - return; - /* Find joystick test multi-purpose display object. */ for(i = 0; i < menu->total_objects; i++) { @@ -200,8 +545,7 @@ static void SARMenuManageOptionsControllerTest( return; /* Redraw joystick test multi-purpose display object. */ - SARMenuDrawObject(display, menu, i); - GWSwapBuffer(display); + DO_REDRAW_OBJECT(display, menu, i); } @@ -223,12 +567,11 @@ void SARMenuManage( if(name != NULL) { #define SAR_MENU_MANAGE_INPUT core_ptr, menu - if(!strcasecmp(name, SAR_MENU_NAME_OPTIONS_CONTROLLER_JS_BTN)) - SARMenuManageOptionsControllerJSButtons(SAR_MENU_MANAGE_INPUT); - else if(!strcasecmp(name, SAR_MENU_NAME_OPTIONS_CONTROLLER_TEST)) - SARMenuManageOptionsControllerTest(SAR_MENU_MANAGE_INPUT); + if(!strcasecmp(name, SAR_MENU_NAME_OPTIONS_CONTROLLER_JS_MAPPING)) + SARMenuManageOptionsControllerJSMapping(SAR_MENU_MANAGE_INPUT); + else if(!strcasecmp(name, SAR_MENU_NAME_OPTIONS_CONTROLLER_JOYSTICK)) + SARMenuManageOptionsControllerJoystick(SAR_MENU_MANAGE_INPUT); #undef SAR_MENU_MANAGE_INPUT } - } #undef SAR_MENU_MANAGE_PROTOTYPE diff --git a/src/sarmenuoptions.c b/src/sarmenuoptions.c index 8d932ce..2bf1e05 100644 --- a/src/sarmenuoptions.c +++ b/src/sarmenuoptions.c @@ -53,13 +53,9 @@ static void SARMenuOptionsSaveMessageBox( sar_core_struct *core_ptr, const char *mesg, const char *path ); -static void SARMenuOptionsJoystickReinit(sar_core_struct *core_ptr); -static void SARMenuOptionsJoystickButtonsRemap(sar_core_struct *core_ptr); -static int SARGetJSButtonFromButtonRoleSpin( - sar_core_struct *core_ptr, - sar_menu_spin_struct *spin, int id - ); +void SARMenuOptionsJoystickReinit(sar_core_struct *core_ptr); +void SARMenuOptionsJoystickMappingReset(sar_core_struct *core_ptr, int gc_js_nums); void SARMenuOptionsJoystickTestDrawCB( void *dpy, /* Display */ void *menu, /* Menu */ @@ -68,6 +64,8 @@ void SARMenuOptionsJoystickTestDrawCB( void *client_data, /* Data */ int x_min, int y_min, int x_max, int y_max ); +void SARMenuOptionsJoystickMappingPrepare(sar_core_struct *core_ptr); +void SARMenuOptionsJoystickMappingExit(sar_core_struct *core_ptr); void SARMenuOptionsGraphicsInfoRefresh(sar_core_struct *core_ptr); static void SARMenuOptionsSaveGraphicsInfoCB(const char *v, void *data); @@ -305,8 +303,9 @@ static void SARMenuOptionsSaveMessageBox( * This will update the gctl structure on the core structure and * opt->gctl_controllers. */ -static void SARMenuOptionsJoystickReinit(sar_core_struct *core_ptr) +void SARMenuOptionsJoystickReinit(sar_core_struct *core_ptr) { +//fprintf(stderr, "%s:%d : Entering SARMenuOptionsJoystickReinit()\n", __FILE__, __LINE__); sar_option_struct *opt; @@ -321,10 +320,69 @@ static void SARMenuOptionsJoystickReinit(sar_core_struct *core_ptr) */ opt->gctl_controllers = GCTL_CONTROLLER_KEYBOARD | GCTL_CONTROLLER_POINTER; - /* Check if one or more joystick(s) need to be enabled */ - if((opt->gctl_js0_axis_roles != 0) || - (opt->gctl_js1_axis_roles != 0) - ) + + if( + (opt->js0_axis_heading < 0) && + (opt->js0_axis_pitch < 0) && + (opt->js0_axis_bank < 0) && + (opt->js0_axis_throttle < 0) && + (opt->js0_pov_hat < 0) && + (opt->js0_axis_hat_x < 0) && + (opt->js0_axis_hat_y < 0) && + (opt->js0_axis_brake_left < 0) && + (opt->js0_axis_brake_right < 0) && + (opt->js0_btn_rotate < 0) && + (opt->js0_btn_air_brakes < 0) && + (opt->js0_btn_wheel_brakes < 0) && + (opt->js0_btn_zoom_in < 0) && + (opt->js0_btn_zoom_out < 0) && + (opt->js0_btn_hoist_up < 0) && + (opt->js0_btn_hoist_down < 0) + ) + strcpy(opt->js0_sdl_guid_s, ""); + if( + (opt->js1_axis_heading < 0) && + (opt->js1_axis_pitch < 0) && + (opt->js1_axis_bank < 0) && + (opt->js1_axis_throttle < 0) && + (opt->js1_pov_hat < 0) && + (opt->js1_axis_hat_x < 0) && + (opt->js1_axis_hat_y < 0) && + (opt->js1_axis_brake_left < 0) && + (opt->js1_axis_brake_right < 0) && + (opt->js1_btn_rotate < 0) && + (opt->js1_btn_air_brakes < 0) && + (opt->js1_btn_wheel_brakes < 0) && + (opt->js1_btn_zoom_in < 0) && + (opt->js1_btn_zoom_out < 0) && + (opt->js1_btn_hoist_up < 0) && + (opt->js1_btn_hoist_down < 0) + ) + strcpy(opt->js1_sdl_guid_s, ""); + if( + (opt->js2_axis_heading < 0) && + (opt->js2_axis_pitch < 0) && + (opt->js2_axis_bank < 0) && + (opt->js2_axis_throttle < 0) && + (opt->js2_pov_hat < 0) && + (opt->js2_axis_hat_x < 0) && + (opt->js2_axis_hat_y < 0) && + (opt->js2_axis_brake_left < 0) && + (opt->js2_axis_brake_right < 0) && + (opt->js2_btn_rotate < 0) && + (opt->js2_btn_air_brakes < 0) && + (opt->js2_btn_wheel_brakes < 0) && + (opt->js2_btn_zoom_in < 0) && + (opt->js2_btn_zoom_out < 0) && + (opt->js2_btn_hoist_up < 0) && + (opt->js2_btn_hoist_down < 0) + ) + strcpy(opt->js2_sdl_guid_s, ""); + + /* Check if joystick(s) need to be enabled */ + if(strlen(opt->js0_sdl_guid_s) != 0 || + strlen(opt->js1_sdl_guid_s) != 0 || + strlen(opt->js2_sdl_guid_s) != 0) { /* Add joystick to game controllers mask */ opt->gctl_controllers |= GCTL_CONTROLLER_JOYSTICK; @@ -334,174 +392,167 @@ static void SARMenuOptionsJoystickReinit(sar_core_struct *core_ptr) GWSetInputBusy(core_ptr->display); SARInitGCTL(core_ptr); /* Realize changes */ GWSetInputReady(core_ptr->display); +//fprintf(stderr, "%s:%d : Exiting SARMenuOptionsJoystickReinit()\n", __FILE__, __LINE__); } + /* - * Checks if the gctl structure on the given core structure has - * one or more joysticks initialized. If so then the joystick - * structures on the gctl structure will have its button mappings - * updated with the global options joystick button mappings. + * Reset joystick(s) mapping spins and axis inversion switches as needed: + * if gc_js_nums bit 'i' is set, then joystick 'i' mapping will be reset. * - * No reinitialization will take place. + * This will only reset spins to 'None' and switches to 'Off' position. + * opt->js*_* values modifications are done by SARMenuOptionsSpinCB(...) + * and SARMenuOptionsSwitchCB(...) call backs. */ -static void SARMenuOptionsJoystickButtonsRemap(sar_core_struct *core_ptr) +void SARMenuOptionsJoystickMappingReset(sar_core_struct *core_ptr, int gc_js_nums) { - gctl_struct *gc; - sar_option_struct *opt; +//fprintf(stderr, "%s:%d : Entering SARMenuOptionsJoystickMappingReset()\n", __FILE__, __LINE__); + //gctl_struct *gc = core_ptr->gctl; + //sar_option_struct *opt; + //gctl_js_struct *gc_js; + gw_display_struct *display; + sar_menu_struct *menu; + sar_menu_spin_struct *spin; + sar_menu_switch_struct *swtch; + int i, jsLastSpin, jsFirstSpin, jsnum, switch_id, switch_num; + //void *menu_object; + //sar_menu_label_struct *label; + + if(gc_js_nums <= 0) + return; if(core_ptr == NULL) return; + //opt = &core_ptr->option; - gc = core_ptr->gctl; - if(gc == NULL) + menu = SARMatchMenuByNamePtr( + core_ptr, + SAR_MENU_NAME_OPTIONS_CONTROLLER_JS_MAPPING + ); + if(menu == NULL) return; - opt = &core_ptr->option; + display = core_ptr->display; + if(display == NULL) + return; - /* Joystick controller defined as one of the game controllers? */ - if(gc->controllers & GCTL_CONTROLLER_JOYSTICK) - { - int i; - gctl_js_struct *gc_js; + for(i = 0; i < menu->total_objects; i++){ + if(SAR_MENU_IS_SPIN(menu->object[i])){ + spin = menu->object[i]; + jsLastSpin = (int)((spin->total_values - 1)/MAX_JOYSTICKS); + jsFirstSpin = jsLastSpin - (int)((spin->total_values - 1)/MAX_JOYSTICKS) + 1; + jsnum = -1; + + if(spin->cur_value >= jsFirstSpin && spin->cur_value <= jsLastSpin) + jsnum = 0; + else if(spin->cur_value > jsLastSpin && spin->cur_value <= jsLastSpin * 2) + jsnum = 1; + else if(spin->cur_value > jsLastSpin * 2 && spin->cur_value <= jsLastSpin * 3) + jsnum = 2; + + /* This spin to reset? */ + if( (jsnum == 0 && (gc_js_nums & 1<<0)) || + (jsnum == 1 && (gc_js_nums & 1<<1)) || + (jsnum == 2 && (gc_js_nums & 1<<2)) + ){ + /* Reset spin */ + + SARMenuSpinSelectValueIndex( + display, menu, i, + 0, // set spin value index to 0 + True + ); + /* Reset inversion switch */ - /* First joystick initialized? */ - i = 0; - if(i < gc->total_joysticks) - gc_js = &gc->joystick[i]; - else - gc_js = NULL; - if(gc_js != NULL) - { - gc_js->button_rotate = opt->js0_btn_rotate; - gc_js->button_air_brakes = opt->js0_btn_air_brakes; - gc_js->button_wheel_brakes = opt->js0_btn_wheel_brakes; - gc_js->button_zoom_in = opt->js0_btn_zoom_in; - gc_js->button_zoom_out = opt->js0_btn_zoom_out; - gc_js->button_hoist_up = opt->js0_btn_hoist_up; - gc_js->button_hoist_down = opt->js0_btn_hoist_down; - } + switch(spin->id){ + case SAR_MENU_ID_OPT_HEADING_AXIS: + switch_id = SAR_MENU_ID_OPT_HEADING_AXIS_INV; + break; + case SAR_MENU_ID_OPT_PITCH_AXIS: + switch_id = SAR_MENU_ID_OPT_PITCH_AXIS_INV; + break; + case SAR_MENU_ID_OPT_BANK_AXIS: + switch_id = SAR_MENU_ID_OPT_BANK_AXIS_INV; + break; + case SAR_MENU_ID_OPT_THROTTLE_AXIS: + switch_id = SAR_MENU_ID_OPT_THROTTLE_AXIS_INV; + break; + case SAR_MENU_ID_OPT_POV_HAT_X: + switch_id = SAR_MENU_ID_OPT_POV_HAT_X_INV; + break; + case SAR_MENU_ID_OPT_POV_HAT_Y: + switch_id = SAR_MENU_ID_OPT_POV_HAT_Y_INV; + break; + case SAR_MENU_ID_OPT_POV_HAT: + switch_id = SAR_MENU_ID_OPT_POV_HAT_INV; + break; + case SAR_MENU_ID_OPT_BRAKE_LEFT_AXIS: + switch_id = SAR_MENU_ID_OPT_BRAKE_LEFT_AXIS_INV; + break; + case SAR_MENU_ID_OPT_BRAKE_RIGHT_AXIS: + switch_id = SAR_MENU_ID_OPT_BRAKE_RIGHT_AXIS_INV; + break; + default: + switch_id = -1; + break; + } - /* Second joystick initialized? */ - i = 1; - if(i < gc->total_joysticks) - gc_js = &gc->joystick[i]; - else - gc_js = NULL; - if(gc_js != NULL) - { - gc_js->button_rotate = opt->js1_btn_rotate; - gc_js->button_air_brakes = opt->js1_btn_air_brakes; - gc_js->button_wheel_brakes = opt->js1_btn_wheel_brakes; - gc_js->button_zoom_in = opt->js1_btn_zoom_in; - gc_js->button_zoom_out = opt->js1_btn_zoom_out; - gc_js->button_hoist_up = opt->js1_btn_hoist_up; - gc_js->button_hoist_down = opt->js1_btn_hoist_down; + if(switch_id >= 0){ + swtch = SARMenuGetObjectByID(menu, switch_id, &switch_num); + SARMenuSwitchSetValue( + display, menu, switch_num, + False, // set switch value to False + True + ); + } + } } - } +//fprintf(stderr, "%s:%d : Exiting SARMenuOptionsJoystickMappingReset()\n", __FILE__, __LINE__); } + /* - * Returns the current joystick button mapping for the given - * joystick action spin's current value. - * - * The given id must be one of SAR_OPT_SELECT_JS#_BUTTON_ACTION - * where # is the joystick number. - * - * Can return -1 on error or if the value is not set. Calling - * function must add 1 to offset when setting to the button spin's - * current value since the button spin's value 0 means button number - * -1 (none/invalid). + * Allocates gc->js_mapping_axes_values before entering joystick mapping menu. */ -static int SARGetJSButtonFromButtonRoleSpin( - sar_core_struct *core_ptr, - sar_menu_spin_struct *spin, int id - ) +void SARMenuOptionsJoystickMappingPrepare(sar_core_struct *core_ptr) { - int val = -1; - const sar_option_struct *opt; - - - if((core_ptr == NULL) || (spin == NULL)) - return(val); - - opt = &core_ptr->option; +//fprintf(stderr, "%s:%d : Entering SARMenuOptionsJoystickMappingPrepare()\n", __FILE__, __LINE__); + gctl_struct *gc = core_ptr->gctl; + gctl_js_mapping_menu_data_struct *axis; + int i, j; + + gc->js_mapping_axes_values = GCTL_JS_MAPPING_MENU_DATA( + malloc(MAX_JOYSTICKS * MAX_JOYSTICK_AXES * + sizeof(gctl_js_mapping_menu_data_struct)) + ); - /* First joystick (js0) */ - if(id == SAR_MENU_ID_OPT_JS0_BUTTON_ACTION) + for(i = 0; i < MAX_JOYSTICKS; i++) { - switch(spin->cur_value) + for(j = 0; j < MAX_JOYSTICK_AXES; j++) { - case 0: /* Rotate Modifier */ - val = opt->js0_btn_rotate; - break; - case 1: /* Air Brakes */ - val = opt->js0_btn_air_brakes; - break; - case 2: /* Wheel Brakes */ - val = opt->js0_btn_wheel_brakes; - break; - case 3: /* Zoom In */ - val = opt->js0_btn_zoom_in; - break; - case 4: /* Zoom out */ - val = opt->js0_btn_zoom_out; - break; - case 5: /* Hoist Up */ - val = opt->js0_btn_hoist_up; - break; - case 6: /* Hoist Down */ - val = opt->js0_btn_hoist_down; - break; -/* When adding a new button mapping, make sure to add it to the - * setting of the button mappings to option structure in - * SARMenuOptionsSpinCB(). - * - * Also make sure to add support for EACH joystick! - */ + axis = &gc->js_mapping_axes_values[i * MAX_JOYSTICK_AXES + j]; + axis->min = 0; + axis->max = 0; } } - /* Second joystick (js1) */ - else if(id == SAR_MENU_ID_OPT_JS1_BUTTON_ACTION) - { - switch(spin->cur_value) - { - case 0: /* Rotate Modifier */ - val = opt->js1_btn_rotate; - break; - case 1: /* Air Brakes */ - val = opt->js1_btn_air_brakes; - break; - case 2: /* Wheel Brakes */ - val = opt->js1_btn_wheel_brakes; - break; - case 3: /* Zoom In */ - val = opt->js1_btn_zoom_in; - break; - case 4: /* Zoom out */ - val = opt->js1_btn_zoom_out; - break; - case 5: /* Hoist Up */ - val = opt->js1_btn_hoist_up; - break; - case 6: /* Hoist Down */ - val = opt->js1_btn_hoist_down; - break; -/* When adding a new button mapping, make sure to add it to the - * setting of the button mappings to option structure in - * SARMenuOptionsSpinCB(). - * - * Also be sure to add support for EACH joystick! + +//fprintf(stderr, "%s:%d : Exiting SARMenuOptionsJoystickMappingPrepare()\n", __FILE__, __LINE__); +} + +/* + * Frees gc->js_mapping_axes_values while exiting joystick mapping menu. */ - } - } +void SARMenuOptionsJoystickMappingExit(sar_core_struct *core_ptr) +{ +//fprintf(stderr, "%s:%d : Entering SARMenuOptionsJoystickMappingExit()\n", __FILE__, __LINE__); + gctl_struct *gc = core_ptr->gctl; - if(val < 0) - val = -1; + free(gc->js_mapping_axes_values); - return(val); +//fprintf(stderr, "%s:%d : Exiting SARMenuOptionsJoystickMappingExit()\n", __FILE__, __LINE__); } @@ -523,6 +574,7 @@ void SARMenuOptionsJoystickTestDrawCB( sar_core_struct *core_ptr = SAR_CORE(client_data); const sar_option_struct *opt; gctl_struct *gc; + SDL_Event event; int w = x_max - x_min, h = y_max - y_min; int fw, fh, width, height; @@ -541,10 +593,34 @@ void SARMenuOptionsJoystickTestDrawCB( 0x7e, 0xfc, 0x7e, 0xfc, 0x7e, 0xfc, 0xfe, 0xfe, 0xc0, 0x06, 0xfe, 0xfe, 0x7e, 0xfc, 0x7e, 0xfc, 0x7e, 0xfc, 0x3e, 0xf8, 0x1f, 0xf0, 0x03, 0x80 }; - /* Button icon bitmap 15x15 */ - const u_int8_t btn_bm[] = { 0x00, 0x00, 0x1f, 0xf0, 0x30, 0x18, - 0x67, 0xcc, 0x4f, 0xe4, 0x5f, 0xf4, 0x5f, 0xf4, 0x5f, 0xf4, 0x5f, 0xf4, - 0x5f, 0xf4, 0x4f, 0xe4, 0x67, 0xcc, 0x30, 0x18, 0x1f, 0xf0, 0x00, 0x00 + + /* Button pressed icon bitmap 22x22 (circle) */ +/* const u_int8_t btn_pressed_bm[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x00, 0x03, 0x03, 0x00, 0x04, + 0x00, 0x80, 0x08, 0x00, 0x40, 0x08, 0x00, 0x40, 0x10, 0x00, 0x20, 0x10, 0x00, 0x20, 0x10, 0x00, + 0x20, 0x10, 0x00, 0x20, 0x10, 0x00, 0x20, 0x10, 0x00, 0x20, 0x08, 0x00, 0x40, 0x08, 0x00, 0x40, + 0x04, 0x00, 0x80, 0x03, 0x03, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00 + }; + */ + + /* Button pressed icon bitmap 22x22 (disc) */ + const u_int8_t btn_pressed_bm[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x00, 0x03, 0xff, 0x00, 0x07, + 0xff, 0x80, 0x0f, 0xff, 0xc0, 0x0f, 0xff, 0xc0, 0x1f, 0xff, 0xe0, 0x1f, 0xff, 0xe0, 0x1f, 0xff, + 0xe0, 0x1f, 0xff, 0xe0, 0x1f, 0xff, 0xe0, 0x1f, 0xff, 0xe0, 0x0f, 0xff, 0xc0, 0x0f, 0xff, 0xc0, + 0x07, 0xff, 0x80, 0x03, 0xff, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00 + }; + + + /* Button released icon bitmap 22x22 */ + const u_int8_t btn_released_bm[] = { + 0x00, 0x00, 0x00, 0x01, 0xfe, 0x00, 0x06, 0x01, 0x80, 0x08, 0x00, 0x40, 0x10, 0x00, 0x20, 0x20, + 0x00, 0x10, 0x20, 0x00, 0x10, 0x40, 0x00, 0x08, 0x40, 0x00, 0x08, 0x40, 0x00, 0x08, 0x40, 0x00, + 0x08, 0x40, 0x00, 0x08, 0x40, 0x00, 0x08, 0x40, 0x00, 0x08, 0x40, 0x00, 0x08, 0x20, 0x00, 0x10, + 0x20, 0x00, 0x10, 0x10, 0x00, 0x20, 0x08, 0x00, 0x40, 0x06, 0x01, 0x80, 0x01, 0xfe, 0x00, 0x00, + 0x00, 0x00 }; if((display == NULL) || (mdpy == NULL) || (core_ptr == NULL)) @@ -573,347 +649,925 @@ void SARMenuOptionsJoystickTestDrawCB( (int)((y) + y_min), \ (s) \ ) +#define COLOR_YELLOW glColor3f(1.0f, 1.0f, 0.0f); +#define COLOR_GREEN glColor3f(0.0f, 1.0f, 0.0f); +#define COLOR_LIGHT_GREEN glColor3f(0.0f, 0.60f, 0.0f); +#define COLOR_GRAY glColor3f(0.50f, 0.50f, 0.50f); +#define COLOR_RED glColor3f(1.0f, 0.0f, 0.0f); +#define COLOR_BLACK glColor3f(0.0f, 0.0f, 0.0f); + + if(gc == NULL) + return; - /* Is game controller initialized to joystick? */ - if((gc != NULL) ? (gc->controllers & GCTL_CONTROLLER_JOYSTICK) : False) + int x, y; + int x_border = 30, y_border = 30; + int x_offset, y_offset, i; + int wc, hc; + const char* s; + gctl_js_struct *gc_joystick; + Boolean gcjs0_set = False, gcjs1_set = False, gcjs2_set = False; + + + /* Open sdl joysticks and map them to gc joysticks */ + GctlJsOpenAndMapp(gc, NULL); + /* Update sdl joysticks axes and buttons values */ + SDL_JoystickUpdate(); + + gc_joystick = &gc->joystick[0]; + if(strlen(gc_joystick->sdl_guid_s) > 0) + gcjs0_set = True; + + gc_joystick = &gc->joystick[1]; + if(strlen(gc_joystick->sdl_guid_s) > 0) + gcjs1_set = True; + + gc_joystick = &gc->joystick[2]; + if(strlen(gc_joystick->sdl_guid_s) > 0) + gcjs2_set = True; + + + /* Calculate bounds for hat grid box */ + x_offset = x_border; + y_offset = y_border; + wc = 50; + hc = 50; + + /* Draw hat grid box */ + if((gcjs0_set && gc->joystick[0].pov_hat > -1) + || (gcjs1_set && gc->joystick[1].pov_hat > -1) + || (gcjs2_set && gc->joystick[2].pov_hat > -1) + || (gcjs0_set && gc->joystick[0].axis_hat_x > -1) + || (gcjs0_set && gc->joystick[0].axis_hat_y > -1) + || (gcjs1_set && gc->joystick[1].axis_hat_x > -1) + || (gcjs1_set && gc->joystick[1].axis_hat_y > -1) + || (gcjs2_set && gc->joystick[2].axis_hat_x > -1) + || (gcjs2_set && gc->joystick[2].axis_hat_y > -1) + ) + COLOR_GREEN + else + COLOR_GRAY + glBegin(GL_LINE_LOOP); + { + SET_VERTEX(x_offset, y_offset); + SET_VERTEX(x_offset, hc + y_offset); + SET_VERTEX(wc + x_offset, hc + y_offset); + SET_VERTEX(wc + x_offset, y_offset); + } + glEnd(); + x = wc / 2; + y = hc / 2; + if((gcjs0_set && gc->joystick[0].pov_hat > -1) + || (gcjs1_set && gc->joystick[1].pov_hat > -1) + || (gcjs2_set && gc->joystick[2].pov_hat > -1) + || (gcjs0_set && gc->joystick[0].axis_hat_x > -1) + || (gcjs0_set && gc->joystick[0].axis_hat_y > -1) + || (gcjs1_set && gc->joystick[1].axis_hat_x > -1) + || (gcjs1_set && gc->joystick[1].axis_hat_y > -1) + || (gcjs2_set && gc->joystick[2].axis_hat_x > -1) + || (gcjs2_set && gc->joystick[2].axis_hat_y > -1) + ) + COLOR_LIGHT_GREEN + else + COLOR_GRAY + glBegin(GL_LINES); { - int js_num, x, y; - int x_border = 30, y_border = 30; - int x_offset, y_offset; - int wc, hc; + SET_VERTEX(x_offset, y + y_offset); + SET_VERTEX(wc + x_offset, y + y_offset); + SET_VERTEX(x + x_offset, y_offset); + SET_VERTEX(x + x_offset, hc + y_offset); + } + glEnd(); + + /* Draw hat */ + x = (int)((gc->hat_x * wc * 0.25) + (wc / 2)); + y = (int)((-gc->hat_y * hc * 0.25) + (hc / 2)); + if((gcjs0_set && gc->joystick[0].pov_hat > -1) + || (gcjs1_set && gc->joystick[1].pov_hat > -1) + || (gcjs2_set && gc->joystick[2].pov_hat > -1) + || (gcjs0_set && gc->joystick[0].axis_hat_x > -1) + || (gcjs0_set && gc->joystick[0].axis_hat_y > -1) + || (gcjs1_set && gc->joystick[1].axis_hat_x > -1) + || (gcjs1_set && gc->joystick[1].axis_hat_y > -1) + || (gcjs2_set && gc->joystick[2].axis_hat_x > -1) + || (gcjs2_set && gc->joystick[2].axis_hat_y > -1) + ) + COLOR_YELLOW + else + COLOR_GRAY + glRasterPos2i( + x - 7 + x_offset + x_min, + height - (y + 7 + y_offset + y_min) + ); + glBitmap(15, 15, 0.0f, 0.0f, 15.0f, 0.0f, hat_bm); - /* Calculate bounds for pitch and bank axis grid box */ - if(w > h) - { - wc = (int)(h - MAX((2 * y_border) + 20, 0)); - hc = (int)(h - MAX((2 * y_border) + 15, 0)); - } - else - { - wc = (int)(w - MAX((2 * x_border) + 20, 0)); - hc = (int)(w - MAX((2 * x_border) + 15, 0)); - } - x_offset = x_border; - y_offset = y_border; - /* Pitch and bank grid box */ - glColor3f(0.0f, 0.75f, 0.0f); - glBegin(GL_LINE_LOOP); - { - SET_VERTEX(x_offset, y_offset); - SET_VERTEX(x_offset, hc + y_offset); - SET_VERTEX(wc + x_offset, hc + y_offset); - SET_VERTEX(wc + x_offset, y_offset); - } - glEnd(); - /* Rudder grid box */ - glBegin(GL_LINE_STRIP); - { - SET_VERTEX(x_offset, hc + y_offset); - SET_VERTEX(x_offset, hc + 15 + y_offset); - SET_VERTEX(wc + x_offset, hc + 15 + y_offset); - SET_VERTEX(wc + x_offset, hc + y_offset); + /* Begin drawing buttons, calculate offsets and starting + * coordinates. Note that the y coordinate will be + * repositioned after each draw and does not need to + * be reset until the "column" shifts. + * + * Set the offsets for the start of drawing this column, + * note that x_offset was already set when drawing the + * hat. + */ + + /* Joysticks buttons roles. + * If role is not assigned, role name color will be gray + * If role is assigned and button released, role name color will be light green + * If role is assigned and button pressed, role name color will be yellow + */ + x = wc + fw; + y_offset = y_border; + y = 0; + + s = "Zoom in"; + if((gcjs0_set && gc->joystick[0].button_zoom_in > -1) + || (gcjs1_set && gc->joystick[1].button_zoom_in > -1) + || (gcjs2_set && gc->joystick[2].button_zoom_in > -1) + ){ + if(gc->zoom_in_state) + COLOR_YELLOW + else + COLOR_LIGHT_GREEN + } + else + COLOR_GRAY + DRAW_STRING(x + x_offset, y + y_offset, s); + y += fh; + + s = "Zoom out"; + if((gcjs0_set && gc->joystick[0].button_zoom_out > -1) + || (gcjs1_set && gc->joystick[1].button_zoom_out > -1) + || (gcjs2_set && gc->joystick[2].button_zoom_out > -1) + ){ + if(gc->zoom_out_state) + COLOR_YELLOW + else + COLOR_LIGHT_GREEN + } + else + COLOR_GRAY + DRAW_STRING(x + x_offset, y + y_offset, s); + y += fh; + + s = "Rotate "; + if((gcjs0_set && gc->joystick[0].button_rotate > -1) + || (gcjs1_set && gc->joystick[1].button_rotate > -1) + || (gcjs2_set && gc->joystick[2].button_rotate > -1) + ){ + if(gc->ctrl_state) + COLOR_YELLOW + else + COLOR_LIGHT_GREEN + } + else + COLOR_GRAY + DRAW_STRING(x + x_offset, y + y_offset, s); + x += STRLEN(s) * fw + 2 * fw; + y -= 2*fh; + + s = "Hoist up"; + if((gcjs0_set && gc->joystick[0].button_hoist_up > -1) + || (gcjs1_set && gc->joystick[1].button_hoist_up > -1) + || (gcjs2_set && gc->joystick[2].button_hoist_up > -1) + ){ + if(gc->hoist_up_state) + COLOR_YELLOW + else + COLOR_LIGHT_GREEN + } + else + COLOR_GRAY + DRAW_STRING(x + x_offset, y + y_offset, s); + y += fh; + + s = "Hoist down"; + if((gcjs0_set && gc->joystick[0].button_hoist_down > -1) + || (gcjs1_set && gc->joystick[1].button_hoist_down > -1) + || (gcjs2_set && gc->joystick[2].button_hoist_down > -1) + ){ + if(gc->hoist_down_state) + COLOR_YELLOW + else + COLOR_LIGHT_GREEN + } + else + COLOR_GRAY + DRAW_STRING(x + x_offset, y + y_offset, s); + x += STRLEN(s) * fw + 2 * fw; + y -= fh; + + if((gcjs0_set && gc->joystick[0].button_air_brakes > -1) + || (gcjs1_set && gc->joystick[1].button_air_brakes > -1) + || (gcjs2_set && gc->joystick[2].button_air_brakes > -1) + ){ + if(gc->air_brakes_state){ + s = "Air brakes [ON]"; + COLOR_YELLOW } - glEnd(); - /* Throttle grid box */ - glBegin(GL_LINE_STRIP); - { - SET_VERTEX(wc + x_offset, y_offset); - SET_VERTEX(wc + 20 + x_offset, y_offset); - SET_VERTEX(wc + 20 + x_offset, hc + 15 + y_offset); + else{ + s = "Air brakes [OFF]"; + COLOR_LIGHT_GREEN } - glEnd(); + } + else{ + s = "Air brakes"; + COLOR_GRAY + } + DRAW_STRING(x + x_offset, y + y_offset, s); + y += fh; + + /* Wheel Brakes, as button or axes */ + + if((gcjs0_set && gc->joystick[0].button_wheel_brakes > -1) + || (gcjs1_set && gc->joystick[1].button_wheel_brakes > -1) + || (gcjs2_set && gc->joystick[2].button_wheel_brakes > -1) + ){ + /* Note 1: shift key state detection works only if window has focus. + * Note 2: wheel brakes to parking brake state transition don't work + * very good on joystick test page but works fine while in game. + */ - /* Center line */ - x = (int)(wc / 2); - y = (int)(hc / 2); - glColor3f(0.0f, 1.0f, 0.0f); - glBegin(GL_LINES); - { - SET_VERTEX(x + x_offset, y_offset); - SET_VERTEX(x + x_offset, hc + 15 + y_offset); - SET_VERTEX(x_offset, y + y_offset); - SET_VERTEX(wc + x_offset, y + y_offset); + /* As we are in a menu, shift key state is not handled by Game + * Controller, thus we read it directly from display. + */ + if(display->shift_key_state && gc->wheel_brakes_state == 1) + gc->wheel_brakes_state = 2; + + switch(gc->wheel_brakes_state){ + case 0: + s = "Wheel brakes [OFF]"; + COLOR_LIGHT_GREEN + break; + case 1: + s = "Wheel brakes [ON]"; + COLOR_YELLOW + break; + case 2: + s = "Parking brake [ON]"; + COLOR_YELLOW + break; + default: + break; } - glEnd(); - /* 25% lines */ - glColor3f(0.0f, 0.75f, 0.0f); - glBegin(GL_LINES); - { - x = (int)(wc * 0.25); - SET_VERTEX(x + x_offset, y_offset); - SET_VERTEX(x + x_offset, hc + 15 + y_offset); - x = (int)(wc * 0.75); - SET_VERTEX(x + x_offset, y_offset); - SET_VERTEX(x + x_offset, hc + 15 + y_offset); - y = (int)(hc * 0.25); - SET_VERTEX(x_offset, y + y_offset); - SET_VERTEX(wc + x_offset, y + y_offset); - y = (int)(hc * 0.75); - SET_VERTEX(x_offset, y + y_offset); - SET_VERTEX(wc + x_offset, y + y_offset); + } + else if((gcjs0_set && gc->joystick[0].axis_brake_left > -1) + || (gcjs0_set && gc->joystick[0].axis_brake_right > -1) + || (gcjs1_set && gc->joystick[1].axis_brake_left > -1) + || (gcjs1_set && gc->joystick[1].axis_brake_right > -1) + || (gcjs2_set && gc->joystick[2].axis_brake_left > -1) + || (gcjs2_set && gc->joystick[2].axis_brake_right > -1) + ){ + /* Note : left and right wheel brake values are handled to an unique + * brake coefficient (see GCtlUpdate()). + */ + + int wheel_brakes_coeff_percents = gc->wheel_brakes_coeff * 100; + + /* As we are in a menu, shift key state is not handled by Game + * Controller, thus we read it directly from display. + */ + if(display->shift_key_state && wheel_brakes_coeff_percents >= 100) + gc->wheel_brakes_state = 2; + + switch(gc->wheel_brakes_state){ + case 0: + s = "Wheel brakes [0%]"; + COLOR_LIGHT_GREEN + break; + case 1: + char ns[48+1]; + snprintf(ns, sizeof(ns), "Wheel brakes [%3d%%]", wheel_brakes_coeff_percents); + s = ns; + if(wheel_brakes_coeff_percents == 0) + COLOR_LIGHT_GREEN + else + COLOR_YELLOW + break; + case 2: + s = "Parking brake [ON]"; + COLOR_YELLOW + break; } - glEnd(); + } + else + { + s = "Wheel brakes"; + COLOR_GRAY + } + DRAW_STRING(x + x_offset, y + y_offset, s); + y -= fh; + x_offset = x_border; + y_offset += wc + 15; + + /* Calculate bounds for pitch and bank axis grid box */ + +/* Max MAX_JOYSTICK_AXES axes per joystick and 6 characters per axis value */ +#define MAX_AXIS_TABLE_PIXELS_WIDTH MAX_JOYSTICK_AXES * 6 * fw + if(w - MAX_AXIS_TABLE_PIXELS_WIDTH > h - hc) + { + hc = (int)(h - MAX((2 * y_border) + 20, 0) - wc - x_border/2); + wc = hc; + } + else + { + wc = (int)(w - MAX((2 * x_border) + 20, 0) - MAX_AXIS_TABLE_PIXELS_WIDTH - x_border/2); + hc = wc; + } +#undef MAX_AXIS_TABLE_PIXELS_WIDTH + + if((gcjs0_set && gc->joystick[0].axis_pitch > -1) + || (gcjs1_set && gc->joystick[1].axis_pitch > -1) + || (gcjs2_set && gc->joystick[2].axis_pitch > -1) + || (gcjs0_set && gc->joystick[0].axis_bank > -1) + || (gcjs1_set && gc->joystick[1].axis_bank > -1) + || (gcjs2_set && gc->joystick[2].axis_bank > -1) + ) + COLOR_GREEN + else + COLOR_GRAY + + /* Pitch and bank grid box */ + glBegin(GL_LINE_LOOP); + { + SET_VERTEX(x_offset, y_offset); + SET_VERTEX(x_offset, hc + y_offset); + SET_VERTEX(wc + x_offset, hc + y_offset); + SET_VERTEX(wc + x_offset, y_offset); + } + glEnd(); + + /* Rudder (heading) grid box */ + if((gcjs0_set && gc->joystick[0].axis_heading > -1) + || (gcjs1_set && gc->joystick[1].axis_heading > -1) + || (gcjs2_set && gc->joystick[2].axis_heading > -1) + || (gcjs0_set && gc->joystick[0].button_rotate > -1 && gc->joystick[0].axis_bank > -1) + || (gcjs1_set && gc->joystick[1].button_rotate > -1 && gc->joystick[1].axis_bank > -1) + || (gcjs2_set && gc->joystick[2].button_rotate > -1 && gc->joystick[2].axis_bank > -1) + ) + COLOR_GREEN + else + COLOR_GRAY + glBegin(GL_LINE_STRIP); + { + SET_VERTEX(x_offset, hc + y_offset); + SET_VERTEX(x_offset, hc + 15 + y_offset); + SET_VERTEX(wc + x_offset, hc + 15 + y_offset); + SET_VERTEX(wc + x_offset, hc + y_offset); + } + glEnd(); + + /* Throttle grid box */ + if((gcjs0_set && gc->joystick[0].axis_throttle > -1) + || (gcjs1_set && gc->joystick[1].axis_throttle > -1) + || (gcjs2_set && gc->joystick[2].axis_throttle > -1) + ) + COLOR_GREEN + else + COLOR_GRAY + glBegin(GL_LINE_STRIP); + { + SET_VERTEX(wc + x_offset, y_offset); + SET_VERTEX(wc + 20 + x_offset, y_offset); + SET_VERTEX(wc + 20 + x_offset, hc + 15 + y_offset); + SET_VERTEX(wc + x_offset, hc + 15 + y_offset); + } + glEnd(); + + /* Pitch center lines */ + x = (int)(wc / 2); + y = (int)(hc / 2); + /* Pitch (horizontal) 25% lines */ + if((gcjs0_set && gc->joystick[0].axis_pitch > -1) + || (gcjs1_set && gc->joystick[1].axis_pitch > -1) + || (gcjs2_set && gc->joystick[2].axis_pitch > -1) + ) + COLOR_LIGHT_GREEN + else + COLOR_GRAY + glBegin(GL_LINES); + { + SET_VERTEX(x_offset, y + y_offset); + SET_VERTEX(wc + x_offset, y + y_offset); + } + glEnd(); + /* Bank center lines */ + x = (int)(wc / 2); + y = (int)(hc / 2); + /* Pitch (horizontal) 25% lines */ + if((gcjs0_set && gc->joystick[0].axis_bank > -1) + || (gcjs1_set && gc->joystick[1].axis_bank > -1) + || (gcjs2_set && gc->joystick[2].axis_bank > -1) + ) + COLOR_LIGHT_GREEN + else + COLOR_GRAY + glBegin(GL_LINES); + { + SET_VERTEX(x + x_offset, y_offset); + SET_VERTEX(x + x_offset, hc + 0 + y_offset); + } + glEnd(); + /* Rudder (heading) center line */ + if((gcjs0_set && gc->joystick[0].axis_heading > -1) + || (gcjs1_set && gc->joystick[1].axis_heading > -1) + || (gcjs2_set && gc->joystick[2].axis_heading > -1) + || (gcjs0_set && gc->joystick[0].button_rotate > -1) + || (gcjs1_set && gc->joystick[1].button_rotate > -1) + || (gcjs2_set && gc->joystick[2].button_rotate > -1) + ) + COLOR_GREEN + else + COLOR_GRAY + glBegin(GL_LINES); + { + SET_VERTEX(x + x_offset, hc + 0 + y_offset); + SET_VERTEX(x + x_offset, hc + 15 + y_offset); + } + glEnd(); + /* Pitch (horizontal) 25% lines */ + if((gcjs0_set && gc->joystick[0].axis_pitch > -1) + || (gcjs1_set && gc->joystick[1].axis_pitch > -1) + || (gcjs2_set && gc->joystick[2].axis_pitch > -1) + ) + COLOR_LIGHT_GREEN + else + COLOR_GRAY + glBegin(GL_LINES); + { + y = (int)(hc * 0.25); + SET_VERTEX(x_offset, y + y_offset); + SET_VERTEX(wc + x_offset, y + y_offset); + y = (int)(hc * 0.75); + SET_VERTEX(x_offset, y + y_offset); + SET_VERTEX(wc + x_offset, y + y_offset); + } + glEnd(); + /* Bank (vertical) 25% lines */ + if((gcjs0_set && gc->joystick[0].axis_bank > -1) + || (gcjs1_set && gc->joystick[1].axis_bank > -1) + || (gcjs2_set && gc->joystick[2].axis_bank > -1) + ) + COLOR_LIGHT_GREEN + else + COLOR_GRAY + glBegin(GL_LINES); + { + x = (int)(wc * 0.25); + SET_VERTEX(x + x_offset, y_offset); + SET_VERTEX(x + x_offset, hc + 0 + y_offset); + x = (int)(wc * 0.75); + SET_VERTEX(x + x_offset, y_offset); + SET_VERTEX(x + x_offset, hc + 0 + y_offset); + } + glEnd(); + + + /* Draw pitch and bank crosshair */ + x = (int)(CLIP(gc->bank, -1, 1) * wc / 2) + (wc / 2); + y = (int)(-CLIP(gc->pitch, -1, 1) * hc / 2) + (hc / 2); + if((gcjs0_set && gc->joystick[0].axis_pitch > -1) + || (gcjs1_set && gc->joystick[1].axis_pitch > -1) + || (gcjs2_set && gc->joystick[2].axis_pitch > -1) + || (gcjs0_set && gc->joystick[0].axis_bank > -1) + || (gcjs1_set && gc->joystick[1].axis_bank > -1) + || (gcjs2_set && gc->joystick[2].axis_bank > -1) + ) + COLOR_YELLOW + else + COLOR_GRAY + glRasterPos2i( + x - 7 + x_offset + x_min, + height - (y + 7 + y_offset + y_min) + ); + glBitmap(15, 15, 0.0f, 0.0f, 15.0f, 0.0f, crosshairs_bm); - /* Draw pitch and bank crosshair */ - x = (int)(CLIP(gc->bank, -1, 1) * wc / 2) + (wc / 2); - y = (int)(-CLIP(gc->pitch, -1, 1) * hc / 2) + (hc / 2); - glColor3f(1.0f, 1.0f, 0.0f); - glRasterPos2i( - x - 7 + x_offset + x_min, - height - (y + 7 + y_offset + y_min) - ); - glBitmap(15, 15, 0.0f, 0.0f, 15.0f, 0.0f, crosshairs_bm); + /* Draw throttle axis */ + hc += 15; + if((gcjs0_set && gc->joystick[0].axis_throttle > -1) + || (gcjs1_set && gc->joystick[1].axis_throttle > -1) + || (gcjs2_set && gc->joystick[2].axis_throttle > -1) + ){ /* Calculate bounds for throttle axis */ - hc += 15; x_offset = x_border + wc; - y_offset = y_border; y = (int)(CLIP(1.0 - gc->throttle, 0, 1) * hc); - - /* Draw throttle axis */ + COLOR_YELLOW glBegin(GL_QUADS); { - SET_VERTEX(0 + x_offset, y + y_offset); - SET_VERTEX(0 + x_offset, hc + y_offset); + SET_VERTEX(1 + x_offset, y + y_offset); + SET_VERTEX(1 + x_offset, hc + y_offset); SET_VERTEX(20 + x_offset, hc + y_offset); SET_VERTEX(20 + x_offset, y + y_offset); } glEnd(); + } - hc -= 15; + hc += 50; + /* Calculate bounds for rudder axis */ + x_offset = x_border; + y_offset = y_border + hc; + x = (int)(CLIP(gc->heading, -1, 1) * (wc / 2)) + (wc / 2); - /* Calculate bounds for rudder axis */ - x_offset = x_border; - y_offset = y_border + hc; - x = (int)(CLIP(gc->heading, -1, 1) * (wc / 2)) + (wc / 2); + /* Draw rudder (heading) axis */ + if((gcjs0_set && gc->joystick[0].axis_heading > -1) + || (gcjs1_set && gc->joystick[1].axis_heading > -1) + || (gcjs2_set && gc->joystick[2].axis_heading > -1) + || (gcjs0_set && gc->joystick[0].button_rotate > -1 && gc->joystick[0].axis_bank > -1) + || (gcjs1_set && gc->joystick[1].button_rotate > -1 && gc->joystick[1].axis_bank > -1) + || (gcjs2_set && gc->joystick[2].button_rotate > -1 && gc->joystick[1].axis_bank > -1) + ) + COLOR_YELLOW + else + COLOR_GRAY + glRasterPos2i( + x - 7 + x_offset + x_min, + height - (15 + y_offset + y_min) + ); + glBitmap(15, 15, 0.0f, 0.0f, 15.0f, 0.0f, rudder_bm); - /* Draw rudder axis */ - glRasterPos2i( - x - 7 + x_offset + x_min, - height - (15 + y_offset + y_min) - ); - glBitmap(15, 15, 0.0f, 0.0f, 15.0f, 0.0f, rudder_bm); + x_offset = x_border + wc + fw + x_border; + y_offset = y_border + 50 + fh; + x = 0; + y = 0; + SDL_Joystick *sdlstick; + int joystick_axes = 0; - /* Calculate bounds for hat grid box */ - x_offset = x_border + wc + 20 + 10; - y_offset = y_border; - wc = 50; - hc = 50; + /* Joystick number, name, axes, buttons, and hats. */ - /* Draw hat grid box */ - glColor3f(0.0f, 0.75f, 0.0f); - glBegin(GL_LINE_LOOP); - { - SET_VERTEX(x_offset, y_offset); - SET_VERTEX(x_offset, hc + y_offset); - SET_VERTEX(wc + x_offset, hc + y_offset); - SET_VERTEX(wc + x_offset, y_offset); - } - glEnd(); - x = wc / 2; - y = hc / 2; - glColor3f(0.0f, 1.0f, 0.0f); - glBegin(GL_LINES); - { - SET_VERTEX(x_offset, y + y_offset); - SET_VERTEX(wc + x_offset, y + y_offset); - SET_VERTEX(x + x_offset, y_offset); - SET_VERTEX(x + x_offset, hc + y_offset); - } - glEnd(); + /* Iterate through all gc joysticks */ + for(i = 0; i < gc->total_joysticks; i++) + { + sdlstick = gc->sdljoystick[i]; - /* Draw hat */ - x = (int)((gc->hat_x * wc * 0.25) + (wc / 2)); - y = (int)((-gc->hat_y * hc * 0.25) + (hc / 2)); - glColor3f(1.0f, 1.0f, 0.0f); - glRasterPos2i( - x - 7 + x_offset + x_min, - height - (y + 7 + y_offset + y_min) - ); - glBitmap(15, 15, 0.0f, 0.0f, 15.0f, 0.0f, hat_bm); - - - /* Begin drawing buttons, calculate offsets and starting - * coordinates. Note that the y coordinate will be - * repositioned after each draw and does not need to - * be reset until the "column" shifts. - * - * Set the offsets for the start of drawing this column, - * ote that x_offset was already set when drawing the - * hat. - */ -/* x_offset = x_border + wc + 20 + x_border; */ - y_offset = y_border + hc + 10; - x = 0; - y = 0; - - /* Buttons pressed on joystick */ - js_num = 0; - if(gc->total_joysticks > js_num) + if(sdlstick != NULL) { - SDL_Joystick *sdljoystick = gc->sdljoystick[js_num]; - int button = -1; + char ns[48+1]; + x = 0; - glColor3f(0.0f, 1.0f, 0.0f); - glRasterPos2i( - x + x_offset + x_min, - height - (15 + y + y_offset + y_min) - ); - glBitmap(15, 15, 0.0f, 0.0f, 15.0f, 0.0f, btn_bm); - x += 15 + 5; - glColor3f(1.0f, 1.0f, 0.0f); + if(gc->total_joysticks > i) + gc_joystick = &gc->joystick[i]; + else + gc_joystick = NULL; - /* This joystick initialized? */ - if (sdljoystick == NULL && SDL_NumJoysticks() > js_num){ - sdljoystick = SDL_JoystickOpen(js_num); - gc->sdljoystick[js_num] = sdljoystick; - } - if (sdljoystick != NULL){ - int i; + /* Joystick number and name */ - /* Look for a currently pressed button */ - for(i = 0; i < SDL_JoystickNumButtons(sdljoystick); i++) + /* This joystick mapped? */ + if( (i == 0 && strlen(opt->js0_sdl_guid_s) > 0) || + (i == 1 && strlen(opt->js1_sdl_guid_s) > 0) || + (i == 2 && strlen(opt->js2_sdl_guid_s) > 0) + ){ + COLOR_GREEN + s = "Joystick #"; + DRAW_STRING(x + x_offset, y + y_offset, s); + x += STRLEN(s) * fw; + COLOR_YELLOW + snprintf(ns, sizeof(ns), "%1d", i + 1); + s = ns; + DRAW_STRING(x + x_offset, y + y_offset, s); + x += STRLEN(s) * fw; + } + else{ + COLOR_RED + s = "[NOT MAPPED]"; + DRAW_STRING(x + x_offset, y + y_offset, s); + x += STRLEN(s) * fw; + } + COLOR_GREEN + s = ": "; + DRAW_STRING(x + x_offset, y + y_offset, s); + x += STRLEN(s) * fw; + COLOR_YELLOW + snprintf(ns, sizeof(ns), "%s", SDL_JoystickName(sdlstick)); + s = ns; + DRAW_STRING(x + x_offset, y + y_offset, s); + + y += fh; + + /* Axes number */ + COLOR_GREEN + x = 0; + s = "Axes: "; + DRAW_STRING(x + x_offset, y + y_offset, s); + x += STRLEN(s) * fw; + COLOR_YELLOW + snprintf(ns, sizeof(ns), "%i", SDL_JoystickNumAxes(sdlstick)); + s = ns; + DRAW_STRING(x + x_offset, y + y_offset, s); + x += STRLEN(s) * fw; + + /* Buttons number*/ + COLOR_GREEN + s = " Buttons: "; + DRAW_STRING(x + x_offset, y + y_offset, s); + x += STRLEN(s) * fw; + COLOR_YELLOW + snprintf(ns, sizeof(ns), "%i", SDL_JoystickNumButtons(sdlstick)); + s = ns; + DRAW_STRING(x + x_offset, y + y_offset, s); + x += STRLEN(s) * fw; + + /* Hats number */ + COLOR_GREEN + s = " POV hats: "; + DRAW_STRING(x + x_offset, y + y_offset, s); + x += STRLEN(s) * fw; + COLOR_YELLOW + snprintf(ns, sizeof(ns), "%i", SDL_JoystickNumHats(sdlstick)); + s = ns; + DRAW_STRING(x + x_offset, y + y_offset, s); + x += STRLEN(s) * fw; + + /* Mapped hat number */ + if(gc_joystick != NULL && gc_joystick->pov_hat > -1){ + for(int k = 0; k < SDL_JoystickNumHats(sdlstick); k++) { - if(SDL_JoystickGetButton(sdljoystick,i)) - { - button = i; + if(k >= MAX_JOYSTICK_HATS) break; + + if(SDL_JoystickGetHat(sdlstick, k) != SDL_HAT_CENTERED){ + COLOR_YELLOW + snprintf(ns, sizeof(ns), " [%i]", gc_joystick->pov_hat + 1); + } + else{ + COLOR_GREEN + snprintf(ns, sizeof(ns), " (%i)", gc_joystick->pov_hat + 1); } } + s = ns; + DRAW_STRING(x + x_offset, y + y_offset, s); + x += STRLEN(s) * fw; } - /* Was a button pressed? */ - if(button > -1) - { - char s[80]; - sprintf(s, "%i", button + 1); - DRAW_STRING( - x + x_offset, - (15 / 2) - (fh / 2) + y + y_offset, - s - ); - x += fw * (STRLEN(s) + 1); - } - y += 15 + 5; - - } - js_num = 1; - if(gc->total_joysticks > js_num) - { - SDL_Joystick *sdljoystick = gc->sdljoystick[js_num]; - int button = -1; - - glColor3f(0.0f, 1.0f, 0.0f); - glRasterPos2i( - x + x_offset + x_min, - height - (15 + y + y_offset + y_min) - ); - glBitmap(15, 15, 0.0f, 0.0f, 15.0f, 0.0f, btn_bm); - x += 15 + 5; - glColor3f(1.0f, 1.0f, 0.0f); + y += 1.2*fh; + + /* Draw axes table */ +#define CHARS_PER_AXIS 6 + joystick_axes = SDL_JoystickNumAxes(sdlstick); + if(joystick_axes > 0 && joystick_axes <= MAX_JOYSTICK_AXES){ + x = 0; + COLOR_GREEN + GLint table_length = CHARS_PER_AXIS * joystick_axes * fw + 1; + /* Horizontal lines */ + glBegin(GL_LINES); + { + SET_VERTEX(x_offset, y + y_offset + 1); + SET_VERTEX(table_length + x_offset, y + 0 * fh + y_offset + 1); - /* This joystick initialized? */ - if (sdljoystick == NULL && SDL_NumJoysticks() > js_num){ - sdljoystick = SDL_JoystickOpen(js_num); - gc->sdljoystick[js_num] = sdljoystick; - } - if (sdljoystick != NULL){ - int i; + SET_VERTEX(x_offset, y + 1 * fh + y_offset + 1); + SET_VERTEX(table_length + x_offset, y + 1 * fh + y_offset + 1); - /* Look for a currently pressed button */ - for(i = 0; i < SDL_JoystickNumButtons(sdljoystick); i++) + SET_VERTEX(x_offset, y + 2 * fh + y_offset + 1); + SET_VERTEX(table_length + x_offset, y + 2 * fh + y_offset + 1); + } + glEnd(); + /* First (left) vertical line */ + glBegin(GL_LINES); { - if(SDL_JoystickGetButton(sdljoystick,i)) + SET_VERTEX(x_offset, y + y_offset + 1); + SET_VERTEX(x_offset, y + 2 * fh + y_offset + 1); + } + glEnd(); + /* Nexts vertical lines */ + for (int k = 1; k <= SDL_JoystickNumAxes(sdlstick); k++){ + glBegin(GL_LINES); { - button = i; - break; + SET_VERTEX(CHARS_PER_AXIS * k * fw + x_offset, y + y_offset + 1); + SET_VERTEX(CHARS_PER_AXIS * k * fw + x_offset, y + 2 * fh + y_offset + 1); } + glEnd(); } } - /* Was a button pressed? */ - if(button > -1) - { - char s[80]; - sprintf(s, "%i", button + 1); - DRAW_STRING( - x + x_offset, - (15 / 2) - (fh / 2) + y + y_offset, - s - ); - x += fw * (STRLEN(s) + 1); - } - y += 15 + 5; - } + /* Fill axis table with roles and values */ + for (int axis_num = 0; axis_num < SDL_JoystickNumAxes(sdlstick); axis_num++){ + if(axis_num > MAX_JOYSTICK_AXES) + break; - /* Joystick names, axises, and buttons */ - x = 0; - y += 5; - for(js_num = 0; js_num < gc->total_joysticks; js_num++) - { - SDL_Joystick *sdljoystick = gc->sdljoystick[js_num]; - if(sdljoystick != NULL) - { - const char* s; - char ns[40]; + /* Print axis role if defined, or just print axis number if not. */ + if(gc_joystick != NULL){ + COLOR_GREEN + /* 's' must have CHARS_PER_AXIS characters */ + if(axis_num == gc_joystick->axis_heading) + s = " Head."; + else if(axis_num == gc_joystick->axis_bank) + s = " Bank"; + else if(axis_num == gc_joystick->axis_pitch) + s = " Pitch"; + else if(axis_num == gc_joystick->axis_throttle) + s = " Thro."; + else if(axis_num == gc_joystick->axis_hat_x) + s = " POV X"; + else if(axis_num == gc_joystick->axis_hat_y) + s = " POV Y"; + else if(axis_num == gc_joystick->axis_brake_left) + s = " L Brk"; + else if(axis_num == gc_joystick->axis_brake_right) + s = " R Brk"; + else{ + snprintf(ns, sizeof(ns), " %2i ", axis_num + 1); + s = ns; + } + } + else{ + COLOR_GRAY + snprintf(ns, sizeof(ns), " %2i ", axis_num + 1); + s = ns; + } - /* Joystick name */ + DRAW_STRING(x + x_offset, y + y_offset, s); + y += fh; - sprintf(ns, "SDL Joystick #%i", js_num); + /* Print axes values */ + /* 'ns' must have CHARS_PER_AXIS characters */ + snprintf(ns, sizeof(ns), "%6i", SDL_JoystickGetAxis(sdlstick, axis_num)); s = ns; - glColor3f(1.0f, 1.0f, 0.0f); + COLOR_YELLOW DRAW_STRING(x + x_offset, y + y_offset, s); - y += fh + 2; - + y -= fh; - /* Axises */ - s = "Axises: "; - glColor3f(0.0f, 1.0f, 0.0f); - DRAW_STRING(x + x_offset, y + y_offset, s); x += STRLEN(s) * fw; + } +#undef CHARS_PER_AXIS + y += 2.2f * fh + 2; - sprintf(ns, "%i", SDL_JoystickNumAxes(sdljoystick)); - s = ns; - glColor3f(1.0f, 1.0f, 0.0f); - DRAW_STRING(x + x_offset, y + y_offset, s); - x += STRLEN(s) * fw; - /* Buttons */ - s = " Buttons: "; - glColor3f(0.0f, 1.0f, 0.0f); - DRAW_STRING(x + x_offset, y + y_offset, s); - x += STRLEN(s) * fw; + /* Joystick buttons */ - sprintf(ns, "%i", SDL_JoystickNumButtons(sdljoystick)); - s = ns; - glColor3f(1.0f, 1.0f, 0.0f); - DRAW_STRING(x + x_offset, y + y_offset, s); - x += STRLEN(s) * fw; + char s_btn_num[2+1]; + x = 0; + for(int k = 0; k < SDL_JoystickNumButtons(sdlstick); k++) + { + if(k >= MAX_JOYSTICK_BTNS) + break; - y += fh; + GLint posX, posY; + + posX = x + x_offset + x_min - 2; + posY = height - (2 + y + y_offset + y_min + fh + 1); + + COLOR_GREEN + glRasterPos2i(posX, posY); + glBitmap(22, 22, 0.0f, 0.0f, 22.0f, 0.0f, btn_released_bm); + + /* Button pressed ? */ + if(SDL_JoystickGetButton(sdlstick, k)) + { + COLOR_YELLOW + glRasterPos2i(posX, posY); + glBitmap(22, 22, 0.0f, 0.0f, 22.0f, 0.0f, btn_pressed_bm); + + COLOR_BLACK + } + else + COLOR_GREEN + + /* Button number */ + snprintf(s_btn_num, sizeof(s_btn_num), "%d", k + 1); + DRAW_STRING( (float)((2 - strlen(s_btn_num)) * fw)/2.0f + x + x_offset, y + y_offset, s_btn_num); + + x += 3 * fw; } + y += 2 * fh; + } + else + { + /* This joystick is not connected */ - y += 5; + /* This joystick not mapped? */ + if(!( (i == 0 && strlen(opt->js0_sdl_guid_s) > 0) || + (i == 1 && strlen(opt->js1_sdl_guid_s) > 0) || + (i == 2 && strlen(opt->js2_sdl_guid_s) > 0) + ) + ) + continue; + + char ns[48+1]; + x = 0; + + COLOR_GREEN + s = "Joystick #"; + DRAW_STRING(x + x_offset, y + y_offset, s); + x += STRLEN(s) * fw; + COLOR_YELLOW + snprintf(ns, sizeof(ns), "%d", i + 1); + s = ns; + DRAW_STRING(x + x_offset, y + y_offset, s); + x += STRLEN(s) * fw; + COLOR_GREEN + s = ": "; + DRAW_STRING(x + x_offset, y + y_offset, s); + x += STRLEN(s) * fw; + COLOR_YELLOW + if(i == 0 && strlen(opt->js0_sdl_guid_s) > 0) + snprintf(ns, sizeof(ns), "%s", opt->js0_sdl_name); + else if(i == 1 && strlen(opt->js1_sdl_guid_s) > 0) + snprintf(ns, sizeof(ns), "%s", opt->js1_sdl_name); + else if(i == 2 && strlen(opt->js2_sdl_guid_s) > 0) + snprintf(ns, sizeof(ns), "%s", opt->js2_sdl_name); + + s = ns; + DRAW_STRING(x + x_offset, y + y_offset, s); + /* x += STRLEN(s) * fw; */ + y += fh; + x = 0; + COLOR_RED + s = "[WARNING: JOYSTICK MAPPED BUT NOT CONNECTED!]"; + DRAW_STRING(x + x_offset, y + y_offset, s); + /* x += STRLEN(s) * fw; */ + + y += 2 * fh; } + } + if(gc->total_sdl_joysticks == 0 && + strlen(opt->js0_sdl_guid_s) == 0 && + strlen(opt->js1_sdl_guid_s) == 0 && + strlen(opt->js2_sdl_guid_s) == 0 + ) + { + const char s0[] = "No Joystick Connected"; + s = s0; + x = x_offset + (w - x_offset) / 2 - ((STRLEN(s) * fw) / 2); + y = (h - y_offset) / 2 + y_offset / 2 - (fh / 2); + COLOR_YELLOW + DRAW_STRING(x, y, s); } + +/* It works, but is it a good idea to forbid access to mapping menu when + * there is no joystick connected? + */ +if(False) +{ + /* Set Mapping button sensivity */ + + int MB_obj_num; + Boolean sensitive; + + if(gc->total_sdl_joysticks == 0) + sensitive = False; else + sensitive = True; + + /* Get "Mapping" button object number on menu page */ + SARMenuGetObjectByID( + menu, + SAR_MENU_ID_GOTO_OPTIONS_CONTROLLER_JS_MAPPING, + &MB_obj_num + ); + + /* Set Mapping button to nonsensitive */ + SARMenuObjectSetSensitive( + display, menu, MB_obj_num, + sensitive, True + ); + + /* Button label object number is button object number - 1 : + * see SARMenuBuildStandardButton() + * and SARMenuBuildOptionsButton(). + * + * Set button label to nonsensitive + */ + SARMenuObjectSetSensitive( + display, menu, MB_obj_num - 1, + sensitive, True + ); +} + + /* Reinit if a joystick is newly plugged or removed */ + + Boolean doJoystickReinit = True; + while(SDL_PollEvent(&event)) { - /* Game controller not initialized to joystick */ - const char s[] = "Joystick Not Initialized"; - int x = (w / 2) - ((STRLEN(s) * fw) / 2), - y = (h / 2) - (fh / 2); - glColor3f(1.0f, 1.0f, 0.0f); - DRAW_STRING(x, y, s); + switch (event.type) + { + case SDL_JOYDEVICEADDED: + case SDL_JOYDEVICEREMOVED: + if(doJoystickReinit){ + SARMenuOptionsJoystickReinit(core_ptr); + + /* Do not reinit one more time during this loop + * if an other joystick was plugged / unplugged . + */ + doJoystickReinit = False; + } + break; + default: + break; + } } +#undef COLOR_BLACK +#undef COLOR_RED +#undef COLOR_LIGHT_GREEN +#undef COLOR_GREEN +#undef COLOR_YELLOW #undef DRAW_STRING #undef SET_VERTEX } @@ -1458,11 +2112,11 @@ void SARMenuOptionsSoundInfoRefresh(sar_core_struct *core_ptr) core_ptr, SAR_MENU_NAME_OPTIONS_SOUND_INFO ); sar_menu_struct *m = (i > -1) ? core_ptr->menu[i] : NULL; - const sar_option_struct *opt; + //const sar_option_struct *opt; if((display == NULL) || (m == NULL)) return; - opt = &core_ptr->option; + //opt = &core_ptr->option; /* Recorder Address */ if((recorder != NULL) && (core_ptr->recorder_address != NULL)) @@ -1726,154 +2380,338 @@ void SARMenuOptionsFetch(sar_core_struct *core_ptr) sw->state = opt->wind; } - /* Menu: Options->Controller */ - i = SARMatchMenuByName(core_ptr, SAR_MENU_NAME_OPTIONS_CONTROLLER); + /* Menu: Options->Controller->Joystick->Mapping */ + i = SARMatchMenuByName(core_ptr, SAR_MENU_NAME_OPTIONS_CONTROLLER_JS_MAPPING); m = ((i < 0) ? NULL : core_ptr->menu[i]); if(m != NULL) { - int connection, priority; - gctl_js_axis_roles axis_roles; + /* Axis mapping spins */ + +#define JS0_FIRST_SPIN_VALUE 1 +#define JS1_FIRST_SPIN_VALUE MAX_JOYSTICK_AXES + 1 +#define JS2_FIRST_SPIN_VALUE 2 * MAX_JOYSTICK_AXES + 1 + + spin = SARMenuOptionsGetSpinByID( + m, SAR_MENU_ID_OPT_HEADING_AXIS, NULL + ); + if(spin != NULL) + { + if(opt->js0_axis_heading > -1) + spin->cur_value = opt->js0_axis_heading + JS0_FIRST_SPIN_VALUE; + else if(opt->js1_axis_heading > -1) + spin->cur_value = opt->js1_axis_heading + JS1_FIRST_SPIN_VALUE; + else if(opt->js2_axis_heading > -1) + spin->cur_value = opt->js2_axis_heading + JS2_FIRST_SPIN_VALUE; + else + spin->cur_value = 0; + } + + spin = SARMenuOptionsGetSpinByID( + m, SAR_MENU_ID_OPT_PITCH_AXIS, NULL + ); + if(spin != NULL) + { + if(opt->js0_axis_pitch > -1) + spin->cur_value = opt->js0_axis_pitch + JS0_FIRST_SPIN_VALUE; + else if(opt->js1_axis_pitch > -1) + spin->cur_value = opt->js1_axis_pitch + JS1_FIRST_SPIN_VALUE; + else if(opt->js2_axis_pitch > -1) + spin->cur_value = opt->js2_axis_pitch + JS2_FIRST_SPIN_VALUE; + else + spin->cur_value = 0; + } + + spin = SARMenuOptionsGetSpinByID( + m, SAR_MENU_ID_OPT_BANK_AXIS, NULL + ); + if(spin != NULL) + { + if(opt->js0_axis_bank > -1) + spin->cur_value = opt->js0_axis_bank + JS0_FIRST_SPIN_VALUE; + else if(opt->js1_axis_bank > -1) + spin->cur_value = opt->js1_axis_bank + JS1_FIRST_SPIN_VALUE; + else if(opt->js2_axis_bank > -1) + spin->cur_value = opt->js2_axis_bank + JS2_FIRST_SPIN_VALUE; + else + spin->cur_value = 0; + } + + spin = SARMenuOptionsGetSpinByID( + m, SAR_MENU_ID_OPT_THROTTLE_AXIS, NULL + ); + if(spin != NULL) + { + if(opt->js0_axis_throttle > -1) + spin->cur_value = opt->js0_axis_throttle + JS0_FIRST_SPIN_VALUE; + else if(opt->js1_axis_throttle > -1) + spin->cur_value = opt->js1_axis_throttle + JS1_FIRST_SPIN_VALUE; + else if(opt->js2_axis_throttle > -1) + spin->cur_value = opt->js2_axis_throttle + JS2_FIRST_SPIN_VALUE; + else + spin->cur_value = 0; + } + + spin = SARMenuOptionsGetSpinByID( + m, SAR_MENU_ID_OPT_BRAKE_LEFT_AXIS, NULL + ); + if(spin != NULL) + { + if(opt->js0_axis_brake_left > -1) + spin->cur_value = opt->js0_axis_brake_left + JS0_FIRST_SPIN_VALUE; + else if(opt->js1_axis_brake_left > -1) + spin->cur_value = opt->js1_axis_brake_left + JS1_FIRST_SPIN_VALUE; + else if(opt->js2_axis_brake_left > -1) + spin->cur_value = opt->js2_axis_brake_left + JS2_FIRST_SPIN_VALUE; + else + spin->cur_value = 0; + } + + spin = SARMenuOptionsGetSpinByID( + m, SAR_MENU_ID_OPT_BRAKE_RIGHT_AXIS, NULL + ); + if(spin != NULL) + { + if(opt->js0_axis_brake_right > -1) + spin->cur_value = opt->js0_axis_brake_right + JS0_FIRST_SPIN_VALUE; + else if(opt->js1_axis_brake_right > -1) + spin->cur_value = opt->js1_axis_brake_right + JS1_FIRST_SPIN_VALUE; + else if(opt->js2_axis_brake_right > -1) + spin->cur_value = opt->js2_axis_brake_right + JS2_FIRST_SPIN_VALUE; + else + spin->cur_value = 0; + } + + spin = SARMenuOptionsGetSpinByID( + m, SAR_MENU_ID_OPT_POV_HAT_X, NULL + ); + if(spin != NULL) + { + if(opt->js0_axis_hat_x > -1) + spin->cur_value = opt->js0_axis_hat_x + JS0_FIRST_SPIN_VALUE; + else if(opt->js1_axis_hat_x > -1) + spin->cur_value = opt->js1_axis_hat_x + JS1_FIRST_SPIN_VALUE; + else if(opt->js2_axis_hat_x > -1) + spin->cur_value = opt->js2_axis_hat_x + JS2_FIRST_SPIN_VALUE; + else + spin->cur_value = 0; + } + + spin = SARMenuOptionsGetSpinByID( + m, SAR_MENU_ID_OPT_POV_HAT_Y, NULL + ); + if(spin != NULL) + { + if(opt->js0_axis_hat_y > -1) + spin->cur_value = opt->js0_axis_hat_y + JS0_FIRST_SPIN_VALUE; + else if(opt->js1_axis_hat_y > -1) + spin->cur_value = opt->js1_axis_hat_y + JS1_FIRST_SPIN_VALUE; + else if(opt->js2_axis_hat_y > -1) + spin->cur_value = opt->js2_axis_hat_y + JS2_FIRST_SPIN_VALUE; + else + spin->cur_value = 0; + } +#undef JS2_FIRST_SPIN_VALUE +#undef JS1_FIRST_SPIN_VALUE +#undef JS0_FIRST_SPIN_VALUE + +#define JS0_FIRST_SPIN_VALUE 1 +#define JS1_FIRST_SPIN_VALUE MAX_JOYSTICK_HATS + 1 +#define JS2_FIRST_SPIN_VALUE 2 * MAX_JOYSTICK_HATS + 1 + spin = SARMenuOptionsGetSpinByID( + m, SAR_MENU_ID_OPT_POV_HAT, NULL + ); + if(spin != NULL) + { + if(opt->js0_pov_hat > -1) + spin->cur_value = opt->js0_pov_hat + JS0_FIRST_SPIN_VALUE; + else if(opt->js1_pov_hat > -1) + spin->cur_value = opt->js1_pov_hat + JS1_FIRST_SPIN_VALUE; + else if(opt->js2_pov_hat > -1) + spin->cur_value = opt->js2_pov_hat + JS2_FIRST_SPIN_VALUE; + else + spin->cur_value = 0; + } +#undef JS2_FIRST_SPIN_VALUE +#undef JS1_FIRST_SPIN_VALUE +#undef JS0_FIRST_SPIN_VALUE + + /* Axis mapping switches */ + + /* Heading axis inversion */ + sw = SARMenuOptionsGetSwitchByID( + m, SAR_MENU_ID_OPT_HEADING_AXIS_INV, NULL + ); + if(sw != NULL) + sw->state = opt->js_axes_inversion_bits & GCTL_JS_AXIS_INV_HEADING; + + /* Pitch axis inversion */ + sw = SARMenuOptionsGetSwitchByID( + m, SAR_MENU_ID_OPT_PITCH_AXIS_INV, NULL + ); + if(sw != NULL) + sw->state = opt->js_axes_inversion_bits & GCTL_JS_AXIS_INV_PITCH; + + /* Bank axis inversion */ + sw = SARMenuOptionsGetSwitchByID( + m, SAR_MENU_ID_OPT_BANK_AXIS_INV, NULL + ); + if(sw != NULL) + sw->state = opt->js_axes_inversion_bits & GCTL_JS_AXIS_INV_BANK; + + /* Throtle axis inversion */ + sw = SARMenuOptionsGetSwitchByID( + m, SAR_MENU_ID_OPT_THROTTLE_AXIS_INV, NULL + ); + if(sw != NULL) + sw->state = opt->js_axes_inversion_bits & GCTL_JS_AXIS_INV_THROTTLE; + + /* POV Hat X axis inversion */ + sw = SARMenuOptionsGetSwitchByID( + m, SAR_MENU_ID_OPT_POV_HAT_X_INV, NULL + ); + if(sw != NULL) + sw->state = opt->js_axes_inversion_bits & GCTL_JS_AXIS_INV_HAT_X; + + /* POV Hat Y axis inversion */ + sw = SARMenuOptionsGetSwitchByID( + m, SAR_MENU_ID_OPT_POV_HAT_Y_INV, NULL + ); + if(sw != NULL) + sw->state = opt->js_axes_inversion_bits & GCTL_JS_AXIS_INV_HAT_Y; + + /* Joystick POV Hat inversion */ + sw = SARMenuOptionsGetSwitchByID( + m, SAR_MENU_ID_OPT_POV_HAT_INV, NULL + ); + if(sw != NULL) + sw->state = opt->js_axes_inversion_bits & GCTL_JS_AXIS_INV_POV_HAT; + + /* Brake Left axis inversion */ + sw = SARMenuOptionsGetSwitchByID( + m, SAR_MENU_ID_OPT_BRAKE_LEFT_AXIS_INV, NULL + ); + if(sw != NULL) + sw->state = opt->js_axes_inversion_bits & GCTL_JS_AXIS_INV_BRAKE_LEFT; + + /* Brake Right axis inversion */ + sw = SARMenuOptionsGetSwitchByID( + m, SAR_MENU_ID_OPT_BRAKE_RIGHT_AXIS_INV, NULL + ); + if(sw != NULL) + sw->state = opt->js_axes_inversion_bits & GCTL_JS_AXIS_INV_BRAKE_RIGHT; + + + /* Buttons mapping spins */ +#define JS0_BTN_FIRST_SPIN_VALUE 1 +#define JS1_BTN_FIRST_SPIN_VALUE MAX_JOYSTICK_BTNS + 1 +#define JS2_BTN_FIRST_SPIN_VALUE 2 * MAX_JOYSTICK_BTNS + 1 + spin = SARMenuOptionsGetSpinByID( + m, SAR_MENU_ID_OPT_ROTATE_BUTTON, NULL + ); + if(spin != NULL) + { + if(opt->js0_btn_rotate > -1) + spin->cur_value = opt->js0_btn_rotate + JS0_BTN_FIRST_SPIN_VALUE; + else if(opt->js1_btn_rotate > -1) + spin->cur_value = opt->js1_btn_rotate + JS1_BTN_FIRST_SPIN_VALUE; + else if(opt->js2_btn_rotate > -1) + spin->cur_value = opt->js2_btn_rotate + JS2_BTN_FIRST_SPIN_VALUE; + else + spin->cur_value = 0; + } + + spin = SARMenuOptionsGetSpinByID( + m, SAR_MENU_ID_OPT_AIR_BRAKES_BUTTON, NULL + ); + if(spin != NULL) + { + if(opt->js0_btn_air_brakes > -1) + spin->cur_value = opt->js0_btn_air_brakes + JS0_BTN_FIRST_SPIN_VALUE; + else if(opt->js1_btn_air_brakes > -1) + spin->cur_value = opt->js1_btn_air_brakes + JS1_BTN_FIRST_SPIN_VALUE; + else if(opt->js2_btn_air_brakes > -1) + spin->cur_value = opt->js2_btn_air_brakes + JS2_BTN_FIRST_SPIN_VALUE; + else + spin->cur_value = 0; + } + + spin = SARMenuOptionsGetSpinByID( + m, SAR_MENU_ID_OPT_WHEEL_BRAKES_BUTTON, NULL + ); + if(spin != NULL) + { + if(opt->js0_btn_wheel_brakes > -1) + spin->cur_value = opt->js0_btn_wheel_brakes + JS0_BTN_FIRST_SPIN_VALUE; + else if(opt->js1_btn_wheel_brakes > -1) + spin->cur_value = opt->js1_btn_wheel_brakes + JS1_BTN_FIRST_SPIN_VALUE; + else if(opt->js2_btn_wheel_brakes > -1) + spin->cur_value = opt->js2_btn_wheel_brakes + JS2_BTN_FIRST_SPIN_VALUE; + else + spin->cur_value = 0; + } - /* Joystick #1 Axis roles */ - axis_roles = opt->gctl_js0_axis_roles; spin = SARMenuOptionsGetSpinByID( - m, SAR_MENU_ID_OPT_JS0_AXISES, NULL + m, SAR_MENU_ID_OPT_ZOOM_IN_BUTTON, NULL ); if(spin != NULL) { - /* These value codes should match those in SARBuildMenus() - * that added these values. - */ - if(axis_roles) - { - if (axis_roles & GCTL_JS_AXIS_ROLE_AS_RUDDER_AND_BRAKES) - spin->cur_value = 10; - else if(axis_roles & GCTL_JS_AXIS_ROLE_AS_THROTTLE_AND_RUDDER) - spin->cur_value = 9; - else if((axis_roles & GCTL_JS_AXIS_ROLE_THROTTLE) && - (axis_roles & GCTL_JS_AXIS_ROLE_HEADING) && - (axis_roles & GCTL_JS_AXIS_ROLE_HAT) - ) - spin->cur_value = 8; - else if((axis_roles & GCTL_JS_AXIS_ROLE_HEADING) && - (axis_roles & GCTL_JS_AXIS_ROLE_HAT) - ) - spin->cur_value = 7; - else if((axis_roles & GCTL_JS_AXIS_ROLE_HEADING) && - (axis_roles & GCTL_JS_AXIS_ROLE_THROTTLE) - ) - spin->cur_value = 6; - else if(axis_roles & GCTL_JS_AXIS_ROLE_HEADING) - spin->cur_value = 5; - else if((axis_roles & GCTL_JS_AXIS_ROLE_THROTTLE) && - (axis_roles & GCTL_JS_AXIS_ROLE_HAT) - ) - spin->cur_value = 4; - else if(axis_roles & GCTL_JS_AXIS_ROLE_HAT) - spin->cur_value = 3; - else if(axis_roles & GCTL_JS_AXIS_ROLE_THROTTLE) - spin->cur_value = 2; - else - spin->cur_value = 1; - } + if(opt->js0_btn_zoom_in > -1) + spin->cur_value = opt->js0_btn_zoom_in + JS0_BTN_FIRST_SPIN_VALUE; + else if(opt->js1_btn_zoom_in > -1) + spin->cur_value = opt->js1_btn_zoom_in + JS1_BTN_FIRST_SPIN_VALUE; + else if(opt->js2_btn_zoom_in > -1) + spin->cur_value = opt->js2_btn_zoom_in + JS2_BTN_FIRST_SPIN_VALUE; else - { spin->cur_value = 0; - } } - /* Joystick #2 Axis roles */ - axis_roles = opt->gctl_js1_axis_roles; spin = SARMenuOptionsGetSpinByID( - m, SAR_MENU_ID_OPT_JS1_AXISES, NULL + m, SAR_MENU_ID_OPT_ZOOM_OUT_BUTTON, NULL ); if(spin != NULL) { - /* These value codes should match those in SARBuildMenus() - * that added these values. - */ - if(axis_roles) - { - if (axis_roles & GCTL_JS_AXIS_ROLE_AS_RUDDER_AND_BRAKES) - spin->cur_value = 10; - else if(axis_roles & GCTL_JS_AXIS_ROLE_AS_THROTTLE_AND_RUDDER) - spin->cur_value = 9; - else if((axis_roles & GCTL_JS_AXIS_ROLE_THROTTLE) && - (axis_roles & GCTL_JS_AXIS_ROLE_HEADING) && - (axis_roles & GCTL_JS_AXIS_ROLE_HAT) - ) - spin->cur_value = 8; - else if((axis_roles & GCTL_JS_AXIS_ROLE_HEADING) && - (axis_roles & GCTL_JS_AXIS_ROLE_HAT) - ) - spin->cur_value = 7; - else if((axis_roles & GCTL_JS_AXIS_ROLE_HEADING) && - (axis_roles & GCTL_JS_AXIS_ROLE_THROTTLE) - ) - spin->cur_value = 6; - else if(axis_roles & GCTL_JS_AXIS_ROLE_HEADING) - spin->cur_value = 5; - else if((axis_roles & GCTL_JS_AXIS_ROLE_THROTTLE) && - (axis_roles & GCTL_JS_AXIS_ROLE_HAT) - ) - spin->cur_value = 4; - else if(axis_roles & GCTL_JS_AXIS_ROLE_HAT) - spin->cur_value = 3; - else if(axis_roles & GCTL_JS_AXIS_ROLE_THROTTLE) - spin->cur_value = 2; - else - spin->cur_value = 1; - } + if(opt->js0_btn_zoom_out > -1) + spin->cur_value = opt->js0_btn_zoom_out + JS0_BTN_FIRST_SPIN_VALUE; + else if(opt->js1_btn_zoom_out > -1) + spin->cur_value = opt->js1_btn_zoom_out + JS1_BTN_FIRST_SPIN_VALUE; + else if(opt->js2_btn_zoom_out > -1) + spin->cur_value = opt->js2_btn_zoom_out + JS2_BTN_FIRST_SPIN_VALUE; else - { spin->cur_value = 0; - } } - } - - /* Menu: Options->Controller->Buttons */ - i = SARMatchMenuByName( - core_ptr, SAR_MENU_NAME_OPTIONS_CONTROLLER_JS_BTN - ); - m = (i > -1) ? core_ptr->menu[i] : NULL; - if(m != NULL) - { - sar_menu_spin_struct *btn_action_spin; - - /* Joystick 1 (js0) button action */ - btn_action_spin = SARMenuOptionsGetSpinByID( - m, SAR_MENU_ID_OPT_JS0_BUTTON_ACTION, NULL - ); spin = SARMenuOptionsGetSpinByID( - m, SAR_MENU_ID_OPT_JS0_BUTTON_NUMBER, NULL + m, SAR_MENU_ID_OPT_HOIST_UP_BUTTON, NULL ); - if((spin != NULL) && (btn_action_spin != NULL)) + if(spin != NULL) { - spin->cur_value = SARGetJSButtonFromButtonRoleSpin( - core_ptr, - btn_action_spin, SAR_MENU_ID_OPT_JS0_BUTTON_ACTION - ) + 1; - if(spin->cur_value >= spin->total_values) + if(opt->js0_btn_hoist_up > -1) + spin->cur_value = opt->js0_btn_hoist_up + JS0_BTN_FIRST_SPIN_VALUE; + else if(opt->js1_btn_hoist_up > -1) + spin->cur_value = opt->js1_btn_hoist_up + JS1_BTN_FIRST_SPIN_VALUE; + else if(opt->js2_btn_hoist_up > -1) + spin->cur_value = opt->js2_btn_hoist_up + JS2_BTN_FIRST_SPIN_VALUE; + else spin->cur_value = 0; } - /* Joystick 2 (js1) button actions */ - btn_action_spin = SARMenuOptionsGetSpinByID( - m, SAR_MENU_ID_OPT_JS1_BUTTON_ACTION, NULL - ); spin = SARMenuOptionsGetSpinByID( - m, SAR_MENU_ID_OPT_JS1_BUTTON_NUMBER, NULL + m, SAR_MENU_ID_OPT_HOIST_DOWN_BUTTON, NULL ); - if((spin != NULL) && (btn_action_spin != NULL)) + if(spin != NULL) { - spin->cur_value = SARGetJSButtonFromButtonRoleSpin( - core_ptr, - btn_action_spin, SAR_MENU_ID_OPT_JS1_BUTTON_ACTION - ) + 1; - if(spin->cur_value >= spin->total_values) + if(opt->js0_btn_hoist_down > -1) + spin->cur_value = opt->js0_btn_hoist_down + JS0_BTN_FIRST_SPIN_VALUE; + else if(opt->js1_btn_hoist_down > -1) + spin->cur_value = opt->js1_btn_hoist_down + JS1_BTN_FIRST_SPIN_VALUE; + else if(opt->js2_btn_hoist_down > -1) + spin->cur_value = opt->js2_btn_hoist_down + JS2_BTN_FIRST_SPIN_VALUE; + else spin->cur_value = 0; } +#undef JS2_BTN_FIRST_SPIN_VALUE +#undef JS1_BTN_FIRST_SPIN_VALUE +#undef JS0_BTN_FIRST_SPIN_VALUE } /* Menu: Options->Graphics */ @@ -2094,10 +2932,6 @@ void SARMenuOptionsButtonCB( switch(id) { - case SAR_MENU_ID_OPT_CONTROLLER_REFRESH: - SARMenuOptionsJoystickReinit(core_ptr); - break; - case SAR_MENU_ID_OPT_GRAPHICS_INFO_SAVE: if(core_ptr->text_input != NULL) { @@ -2159,14 +2993,15 @@ void SARMenuOptionsSwitchCB( Boolean state ) { +//fprintf(stderr, "%s:%d: Entering SARMenuOptionsSwitchCB()\n", __FILE__, __LINE__); sar_core_struct *core_ptr = SAR_CORE(client_data); - gw_display_struct *display; + //gw_display_struct *display; sar_menu_switch_struct *sw = (sar_menu_switch_struct *)object; sar_option_struct *opt; if((core_ptr == NULL) || (sw == NULL)) return; - display = core_ptr->display; + //display = core_ptr->display; opt = &core_ptr->option; /* Handle by switch's ID code */ @@ -2229,7 +3064,71 @@ to visually interprite heightfield objects." case SAR_MENU_ID_OPT_WIND: opt->wind = state; break; + + case SAR_MENU_ID_OPT_HEADING_AXIS_INV: + if(state) + opt->js_axes_inversion_bits |= GCTL_JS_AXIS_INV_HEADING; + else + opt->js_axes_inversion_bits &= ~GCTL_JS_AXIS_INV_HEADING; + break; + + case SAR_MENU_ID_OPT_PITCH_AXIS_INV: + if(state) + opt->js_axes_inversion_bits |= GCTL_JS_AXIS_INV_PITCH; + else + opt->js_axes_inversion_bits &= ~GCTL_JS_AXIS_INV_PITCH; + break; + + case SAR_MENU_ID_OPT_BANK_AXIS_INV: + if(state) + opt->js_axes_inversion_bits |= GCTL_JS_AXIS_INV_BANK; + else + opt->js_axes_inversion_bits &= ~GCTL_JS_AXIS_INV_BANK; + break; + + case SAR_MENU_ID_OPT_THROTTLE_AXIS_INV: + if(state) + opt->js_axes_inversion_bits |= GCTL_JS_AXIS_INV_THROTTLE; + else + opt->js_axes_inversion_bits &= ~GCTL_JS_AXIS_INV_THROTTLE; + break; + + case SAR_MENU_ID_OPT_BRAKE_LEFT_AXIS_INV: + if(state) + opt->js_axes_inversion_bits |= GCTL_JS_AXIS_INV_BRAKE_LEFT; + else + opt->js_axes_inversion_bits &= ~GCTL_JS_AXIS_INV_BRAKE_LEFT; + break; + + case SAR_MENU_ID_OPT_BRAKE_RIGHT_AXIS_INV: + if(state) + opt->js_axes_inversion_bits |= GCTL_JS_AXIS_INV_BRAKE_RIGHT; + else + opt->js_axes_inversion_bits &= ~GCTL_JS_AXIS_INV_BRAKE_RIGHT; + break; + + case SAR_MENU_ID_OPT_POV_HAT_INV: + if(state) + opt->js_axes_inversion_bits |= GCTL_JS_AXIS_INV_POV_HAT; + else + opt->js_axes_inversion_bits &= ~GCTL_JS_AXIS_INV_POV_HAT; + break; + + case SAR_MENU_ID_OPT_POV_HAT_X_INV: + if(state) + opt->js_axes_inversion_bits |= GCTL_JS_AXIS_INV_HAT_X; + else + opt->js_axes_inversion_bits &= ~GCTL_JS_AXIS_INV_HAT_X; + break; + + case SAR_MENU_ID_OPT_POV_HAT_Y_INV: + if(state) + opt->js_axes_inversion_bits |= GCTL_JS_AXIS_INV_HAT_Y; + else + opt->js_axes_inversion_bits &= ~GCTL_JS_AXIS_INV_HAT_Y; + break; } +//fprintf(stderr, "%s:%d: Exiting SARMenuOptionsSwitchCB()\n", __FILE__, __LINE__); } /* @@ -2240,12 +3139,14 @@ void SARMenuOptionsSpinCB( char *value ) { +//fprintf(stderr, "%s:%d: Entering SARMenuOptionsSpinCB()\n", __FILE__, __LINE__); const char *sound_server_connect_arg = "127.0.0.1:9433"; sar_menu_struct *m; gw_display_struct *display; sar_core_struct *core_ptr = SAR_CORE(client_data); sar_menu_spin_struct *spin = SAR_MENU_SPIN(object); sar_option_struct *opt; + if((core_ptr == NULL) || (spin == NULL)) return; @@ -2340,288 +3241,614 @@ void SARMenuOptionsSpinCB( break; } break; - case SAR_MENU_ID_OPT_JS0_AXISES: - /* These values should correspond to those used to - * set the values in SARBuildMenus(). - */ -#define JS_AXIS_ROLES opt->gctl_js0_axis_roles - JS_AXIS_ROLES = 0; - switch(spin->cur_value) - { - case 1: /* 2D */ - JS_AXIS_ROLES |= GCTL_JS_AXIS_ROLE_PITCH | - GCTL_JS_AXIS_ROLE_BANK; - break; - - case 2: /* 2D with throttle */ - JS_AXIS_ROLES |= GCTL_JS_AXIS_ROLE_PITCH | - GCTL_JS_AXIS_ROLE_BANK | GCTL_JS_AXIS_ROLE_THROTTLE; - break; - case 3: /* 2D with hat */ - JS_AXIS_ROLES |= GCTL_JS_AXIS_ROLE_PITCH | - GCTL_JS_AXIS_ROLE_BANK | GCTL_JS_AXIS_ROLE_HAT; - break; +#define JS1_FIRST_SPIN_VALUE MAX_JOYSTICK_AXES + 1 +#define JS2_FIRST_SPIN_VALUE 2 * MAX_JOYSTICK_AXES + 1 +#define JS2_LAST_SPIN_VALUE 3 * MAX_JOYSTICK_AXES + case SAR_MENU_ID_OPT_HEADING_AXIS: + if(spin->cur_value == 0){ + opt->js0_axis_heading = -1; + opt->js1_axis_heading = -1; + opt->js2_axis_heading = -1; + break; + } + else{ + /* As Heading is mapped to an axis, force Rotate button + * spin value to None. + */ + + /* Get Rotate button spin object number on menu page */ + int spin_num; + SARMenuGetObjectByID( + m, SAR_MENU_ID_OPT_ROTATE_BUTTON, &spin_num + ); + /* Set Rotate spin value to 0 */ + SARMenuSpinSelectValueIndex( + display, m, spin_num, 0, True + ); - case 4: /* 2D with throttle & hat */ - JS_AXIS_ROLES |= GCTL_JS_AXIS_ROLE_PITCH | - GCTL_JS_AXIS_ROLE_BANK | GCTL_JS_AXIS_ROLE_THROTTLE | - GCTL_JS_AXIS_ROLE_HAT; - break; + if(spin->cur_value < JS1_FIRST_SPIN_VALUE){ + opt->js0_axis_heading = spin->cur_value - 1; + opt->js1_axis_heading = -1; + opt->js2_axis_heading = -1; + } + else if(spin->cur_value < JS2_FIRST_SPIN_VALUE){ + opt->js0_axis_heading = -1; + opt->js1_axis_heading = spin->cur_value - JS1_FIRST_SPIN_VALUE - 2; + opt->js2_axis_heading = -1; + } + else if(spin->cur_value <= JS2_LAST_SPIN_VALUE){ + opt->js0_axis_heading = -1; + opt->js1_axis_heading = -1; + opt->js2_axis_heading = spin->cur_value - JS2_FIRST_SPIN_VALUE - 2; + } + else + ; + } + break; - case 5: /* 3D */ - JS_AXIS_ROLES |= GCTL_JS_AXIS_ROLE_PITCH | - GCTL_JS_AXIS_ROLE_BANK | GCTL_JS_AXIS_ROLE_HEADING; - break; + case SAR_MENU_ID_OPT_PITCH_AXIS: + if(spin->cur_value == 0){ + opt->js0_axis_pitch = -1; + opt->js1_axis_pitch = -1; + opt->js2_axis_pitch = -1; + break; + } + else if(spin->cur_value < JS1_FIRST_SPIN_VALUE){ + opt->js0_axis_pitch = spin->cur_value - 1; + opt->js1_axis_pitch = -1; + opt->js2_axis_pitch = -1; + } + else if(spin->cur_value < JS2_FIRST_SPIN_VALUE){ + opt->js0_axis_pitch = -1; + opt->js1_axis_pitch = spin->cur_value - JS1_FIRST_SPIN_VALUE - 2; + opt->js2_axis_pitch = -1; + } + else if(spin->cur_value <= JS2_LAST_SPIN_VALUE){ + opt->js0_axis_pitch = -1; + opt->js1_axis_pitch = -1; + opt->js2_axis_pitch = spin->cur_value - JS2_FIRST_SPIN_VALUE - 2; + } + else + ; + break; - case 6: /* 3D with throttle */ - JS_AXIS_ROLES |= GCTL_JS_AXIS_ROLE_PITCH | - GCTL_JS_AXIS_ROLE_BANK | GCTL_JS_AXIS_ROLE_HEADING | - GCTL_JS_AXIS_ROLE_THROTTLE; - break; + case SAR_MENU_ID_OPT_BANK_AXIS: + if(spin->cur_value == 0){ + opt->js0_axis_bank = -1; + opt->js1_axis_bank = -1; + opt->js2_axis_bank = -1; + break; + } + else if(spin->cur_value < JS1_FIRST_SPIN_VALUE){ + opt->js0_axis_bank = spin->cur_value - 1; + opt->js1_axis_bank = -1; + opt->js2_axis_bank = -1; + } + else if(spin->cur_value < JS2_FIRST_SPIN_VALUE){ + opt->js0_axis_bank = -1; + opt->js1_axis_bank = spin->cur_value - JS1_FIRST_SPIN_VALUE - 2; + opt->js2_axis_bank = -1; + } + else if(spin->cur_value <= JS2_LAST_SPIN_VALUE){ + opt->js0_axis_bank = -1; + opt->js1_axis_bank = -1; + opt->js2_axis_bank = spin->cur_value - JS2_FIRST_SPIN_VALUE - 2; + } + else + ; + break; - case 7: /* 3D with hat */ - JS_AXIS_ROLES |= GCTL_JS_AXIS_ROLE_PITCH | - GCTL_JS_AXIS_ROLE_BANK | GCTL_JS_AXIS_ROLE_HEADING | - GCTL_JS_AXIS_ROLE_HAT; - break; + case SAR_MENU_ID_OPT_THROTTLE_AXIS: + if(spin->cur_value == 0){ + opt->js0_axis_throttle = -1; + opt->js1_axis_throttle = -1; + opt->js2_axis_throttle = -1; + break; + } + else if(spin->cur_value < JS1_FIRST_SPIN_VALUE){ + opt->js0_axis_throttle = spin->cur_value - 1; + opt->js1_axis_throttle = -1; + opt->js2_axis_throttle = -1; + } + else if(spin->cur_value < JS2_FIRST_SPIN_VALUE){ + opt->js0_axis_throttle = -1; + opt->js1_axis_throttle = spin->cur_value - JS1_FIRST_SPIN_VALUE - 2; + opt->js2_axis_throttle = -1; + } + else if(spin->cur_value <= JS2_LAST_SPIN_VALUE){ + opt->js0_axis_throttle = -1; + opt->js1_axis_throttle = -1; + opt->js2_axis_throttle = spin->cur_value - JS2_FIRST_SPIN_VALUE - 2; + } + else + ; + break; - case 8: /* 3D with throttle & hat */ - JS_AXIS_ROLES |= GCTL_JS_AXIS_ROLE_PITCH | - GCTL_JS_AXIS_ROLE_BANK | GCTL_JS_AXIS_ROLE_HEADING | - GCTL_JS_AXIS_ROLE_THROTTLE | GCTL_JS_AXIS_ROLE_HAT; - break; + case SAR_MENU_ID_OPT_BRAKE_LEFT_AXIS: + if(spin->cur_value == 0){ + opt->js0_axis_brake_left = -1; + opt->js1_axis_brake_left = -1; + opt->js2_axis_brake_left = -1; + break; + } + else{ + /* As Left Wheel Break is mapped to an axis, force Wheel Break + * button spin value to None. + */ + + /* Get Wheel Brake button spin object number on menu page */ + int spin_num; + SARMenuGetObjectByID( + m, SAR_MENU_ID_OPT_WHEEL_BRAKES_BUTTON, &spin_num + ); + /* Set Wheel Brake spin value to 0 */ + SARMenuSpinSelectValueIndex( + display, m, spin_num, 0, True + ); - case 9: /* As throttle & rudder */ - JS_AXIS_ROLES |= GCTL_JS_AXIS_ROLE_AS_THROTTLE_AND_RUDDER; - break; - case 10: /* As rudder & brakes */ - JS_AXIS_ROLES |= GCTL_JS_AXIS_ROLE_AS_RUDDER_AND_BRAKES; - break; + if(spin->cur_value < JS1_FIRST_SPIN_VALUE){ + opt->js0_axis_brake_left = spin->cur_value - 1; + opt->js1_axis_brake_left = -1; + opt->js2_axis_brake_left = -1; + } + else if(spin->cur_value < JS2_FIRST_SPIN_VALUE){ + opt->js0_axis_brake_left = -1; + opt->js1_axis_brake_left = spin->cur_value - JS1_FIRST_SPIN_VALUE - 2; + opt->js2_axis_brake_left = -1; + } + else if(spin->cur_value <= JS2_LAST_SPIN_VALUE){ + opt->js0_axis_brake_left = -1; + opt->js1_axis_brake_left = -1; + opt->js2_axis_brake_left = spin->cur_value - JS2_FIRST_SPIN_VALUE - 2; + } + else + ; } -#undef JS_AXIS_ROLES - /* Update options.controllers mask and reinitialize the - * game controller. - */ - SARMenuOptionsJoystickReinit(core_ptr); break; - case SAR_MENU_ID_OPT_JS1_AXISES: - /* These values should correspond to those used to - * set the values in SARBuildMenus(). - */ -#define JS_AXIS_ROLES opt->gctl_js1_axis_roles - JS_AXIS_ROLES = 0; - switch(spin->cur_value) - { - case 1: /* 2D */ - JS_AXIS_ROLES |= GCTL_JS_AXIS_ROLE_PITCH | - GCTL_JS_AXIS_ROLE_BANK; - break; + case SAR_MENU_ID_OPT_BRAKE_RIGHT_AXIS: + if(spin->cur_value == 0){ + opt->js0_axis_brake_right = -1; + opt->js1_axis_brake_right = -1; + opt->js2_axis_brake_right = -1; + break; + } + else{ + /* As right Wheel Break is mapped to an axis, force Wheel Break + * button spin value to None. + */ + + /* Get Wheel Brake button spin object number on menu page */ + int spin_num; + SARMenuGetObjectByID( + m, SAR_MENU_ID_OPT_WHEEL_BRAKES_BUTTON, &spin_num + ); + /* Set Wheel Brake spin value to 0 */ + SARMenuSpinSelectValueIndex( + display, m, spin_num, 0, True + ); - case 2: /* 2D with throttle */ - JS_AXIS_ROLES |= GCTL_JS_AXIS_ROLE_PITCH | - GCTL_JS_AXIS_ROLE_BANK | GCTL_JS_AXIS_ROLE_THROTTLE; - break; + if(spin->cur_value < JS1_FIRST_SPIN_VALUE){ + opt->js0_axis_brake_right = spin->cur_value - 1; + opt->js1_axis_brake_right = -1; + opt->js2_axis_brake_right = -1; + } + else if(spin->cur_value < JS2_FIRST_SPIN_VALUE){ + opt->js0_axis_brake_right = -1; + opt->js1_axis_brake_right = spin->cur_value - JS1_FIRST_SPIN_VALUE - 2; + opt->js2_axis_brake_right = -1; + } + else if(spin->cur_value <= JS2_LAST_SPIN_VALUE){ + opt->js0_axis_brake_right = -1; + opt->js1_axis_brake_right = -1; + opt->js2_axis_brake_right = spin->cur_value - JS2_FIRST_SPIN_VALUE - 2; + } + else + ; + } + break; - case 3: /* 2D with hat */ - JS_AXIS_ROLES |= GCTL_JS_AXIS_ROLE_PITCH | - GCTL_JS_AXIS_ROLE_BANK | GCTL_JS_AXIS_ROLE_HAT; - break; + case SAR_MENU_ID_OPT_POV_HAT_X: + if(spin->cur_value == 0){ + opt->js0_axis_hat_x = -1; + opt->js1_axis_hat_x = -1; + opt->js2_axis_hat_x = -1; + } + else{ + /* As POV X is mapped to an analog axis, force "POV Hat" spin + * value to None. + */ + + /* Get "POV Hat" spin object number on menu page */ + int spin_num; + SARMenuGetObjectByID( + m, SAR_MENU_ID_OPT_POV_HAT, &spin_num + ); + /* Set "POV Hat" spin value to 0 */ + SARMenuSpinSelectValueIndex( + display, m, spin_num, 0, True + ); - case 4: /* 2D with throttle & hat */ - JS_AXIS_ROLES |= GCTL_JS_AXIS_ROLE_PITCH | - GCTL_JS_AXIS_ROLE_BANK | GCTL_JS_AXIS_ROLE_THROTTLE | - GCTL_JS_AXIS_ROLE_HAT; - break; + /* Set option value */ + if(spin->cur_value < JS1_FIRST_SPIN_VALUE){ + opt->js0_axis_hat_x = spin->cur_value - 1; + opt->js1_axis_hat_x = -1; + opt->js2_axis_hat_x = -1; + } + else if(spin->cur_value < JS2_FIRST_SPIN_VALUE) + { + opt->js0_axis_hat_x = -1; + opt->js1_axis_hat_x = spin->cur_value - JS1_FIRST_SPIN_VALUE - 2; + opt->js2_axis_hat_x = -1; + } + else if(spin->cur_value <= JS2_LAST_SPIN_VALUE) + { + opt->js0_axis_hat_x = -1; + opt->js1_axis_hat_x = -1; + opt->js2_axis_hat_x = spin->cur_value - JS2_FIRST_SPIN_VALUE - 2; + } - case 5: /* 3D */ - JS_AXIS_ROLES |= GCTL_JS_AXIS_ROLE_PITCH | - GCTL_JS_AXIS_ROLE_BANK | GCTL_JS_AXIS_ROLE_HEADING; - break; + /* Clear standard hat values */ + opt->js0_pov_hat = -1; + opt->js1_pov_hat = -1; + opt->js2_pov_hat = -1; + } + break; - case 6: /* 3D with throttle */ - JS_AXIS_ROLES |= GCTL_JS_AXIS_ROLE_PITCH | - GCTL_JS_AXIS_ROLE_BANK | GCTL_JS_AXIS_ROLE_HEADING | - GCTL_JS_AXIS_ROLE_THROTTLE; - break; + case SAR_MENU_ID_OPT_POV_HAT_Y: + if(spin->cur_value == 0){ + opt->js0_axis_hat_y = -1; + opt->js1_axis_hat_y = -1; + opt->js2_axis_hat_y = -1; + } + else{ + /* As POV Y is mapped to an analog axis, force "POV Hat" spin + * value to None. + */ + + /* Get "POV Hat" spin object number on menu page */ + int spin_num; + SARMenuGetObjectByID( + m, SAR_MENU_ID_OPT_POV_HAT, &spin_num + ); + /* Set "POV Hat" spin value to 0 */ + SARMenuSpinSelectValueIndex( + display, m, spin_num, 0, True + ); - case 7: /* 3D with hat */ - JS_AXIS_ROLES |= GCTL_JS_AXIS_ROLE_PITCH | - GCTL_JS_AXIS_ROLE_BANK | GCTL_JS_AXIS_ROLE_HEADING | - GCTL_JS_AXIS_ROLE_HAT; - break; + /* Set option value */ + if(spin->cur_value < JS1_FIRST_SPIN_VALUE){ + opt->js0_axis_hat_y = spin->cur_value - 1; + opt->js1_axis_hat_y = -1; + opt->js2_axis_hat_y = -1; + } + else if(spin->cur_value < JS2_FIRST_SPIN_VALUE){ + opt->js0_axis_hat_y = -1; + opt->js1_axis_hat_y = spin->cur_value - JS1_FIRST_SPIN_VALUE - 2; + opt->js2_axis_hat_y = -1; + } + else if(spin->cur_value <= JS2_LAST_SPIN_VALUE){ + opt->js0_axis_hat_y = -1; + opt->js1_axis_hat_y = -1; + opt->js2_axis_hat_y = spin->cur_value - JS2_FIRST_SPIN_VALUE - 2; + } - case 8: /* 3D with throttle & hat */ - JS_AXIS_ROLES |= GCTL_JS_AXIS_ROLE_PITCH | - GCTL_JS_AXIS_ROLE_BANK | GCTL_JS_AXIS_ROLE_HEADING | - GCTL_JS_AXIS_ROLE_THROTTLE | GCTL_JS_AXIS_ROLE_HAT; - break; + /* Clear standard hat values */ + opt->js0_pov_hat = -1; + opt->js1_pov_hat = -1; + opt->js2_pov_hat = -1; + } + break; +#undef JS2_LAST_SPIN_VALUE +#undef JS2_FIRST_SPIN_VALUE +#undef JS1_FIRST_SPIN_VALUE + +#define JS1_FIRST_SPIN_VALUE MAX_JOYSTICK_HATS + 1 +#define JS2_FIRST_SPIN_VALUE 2 * MAX_JOYSTICK_HATS + 1 +#define JS2_LAST_SPIN_VALUE 3 * MAX_JOYSTICK_HATS + case SAR_MENU_ID_OPT_POV_HAT: + if(spin->cur_value == 0){ + opt->js0_pov_hat = -1; + opt->js1_pov_hat = -1; + opt->js2_pov_hat = -1; + break; + } + else{ + /* As POV Hat is mapped to a joystick standard hat, force + * "POV X Axis" and "POV Y Axis" spins value to None. + */ + + /* Get "POV X Axis" spin object number */ + int spin_num; + SARMenuGetObjectByID( + m, SAR_MENU_ID_OPT_POV_HAT_X, &spin_num + ); + /* Set "POV X Axis" spin value to 0 */ + SARMenuSpinSelectValueIndex( + display, m, spin_num, 0, True + ); + /* Get "POV Y Axis" spin object number */ + SARMenuGetObjectByID( + m, SAR_MENU_ID_OPT_POV_HAT_Y, &spin_num + ); + /* Set "POV Y axis" spin value to 0 */ + SARMenuSpinSelectValueIndex( + display, m, spin_num, 0, True + ); - case 9: /* As throttle & rudder */ - JS_AXIS_ROLES |= GCTL_JS_AXIS_ROLE_AS_THROTTLE_AND_RUDDER; - break; - case 10: /* As rudder & brakes */ - JS_AXIS_ROLES |= GCTL_JS_AXIS_ROLE_AS_RUDDER_AND_BRAKES; + /* Set option value */ + if(spin->cur_value < JS1_FIRST_SPIN_VALUE){ + /* Joystick 1 Hat 1 or Hat 2 */ + opt->js0_pov_hat = spin->cur_value - 1; + opt->js1_pov_hat = -1; + opt->js2_pov_hat = -1; + } + else if(spin->cur_value < JS2_FIRST_SPIN_VALUE){ + /* Joystick 2 Hat 1 or Hat 2 */ + opt->js0_pov_hat = -1; + opt->js1_pov_hat = spin->cur_value - JS1_FIRST_SPIN_VALUE - 2; + opt->js2_pov_hat = -1; + } + else if(spin->cur_value <= JS2_LAST_SPIN_VALUE){ + /* Joystick 3 Hat 1 or Hat 2 */ + opt->js0_pov_hat = -1; + opt->js1_pov_hat = -1; + opt->js2_pov_hat = spin->cur_value - JS2_FIRST_SPIN_VALUE - 2; + } - break; + /* Clear x and y axes values */ + opt->js0_axis_hat_x = -1; + opt->js0_axis_hat_y = -1; + opt->js1_axis_hat_x = -1; + opt->js1_axis_hat_y = -1; + opt->js2_axis_hat_x = -1; + opt->js2_axis_hat_y = -1; } -#undef JS_AXIS_ROLES - /* Update options.controllers mask and reinitialize the - * game controller. - */ - SARMenuOptionsJoystickReinit(core_ptr); break; +#undef JS2_LAST_SPIN_VALUE +#undef JS2_FIRST_SPIN_VALUE +#undef JS1_FIRST_SPIN_VALUE + +#define JS1_FIRST_SPIN_VALUE MAX_JOYSTICK_BTNS + 1 +#define JS2_FIRST_SPIN_VALUE 2 * MAX_JOYSTICK_BTNS + 1 +#define JS2_LAST_SPIN_VALUE 3 * MAX_JOYSTICK_BTNS + case SAR_MENU_ID_OPT_ROTATE_BUTTON: + if(spin->cur_value == 0){ + opt->js0_btn_rotate = -1; + opt->js1_btn_rotate = -1; + opt->js2_btn_rotate = -1; + } + else{ + /* As Rotate function is mapped to a button, force Heading axis + * spin value to "None". + */ + + /* Get Heading axis spin object number on menu page */ + int spin_num; + SARMenuGetObjectByID( + m, SAR_MENU_ID_OPT_HEADING_AXIS, &spin_num + ); + /* Set Heading spin value to 0 */ + SARMenuSpinSelectValueIndex( + display, m, spin_num, 0, True + ); - case SAR_MENU_ID_OPT_JS0_BUTTON_ACTION: + /* Set option value */ + if(spin->cur_value < JS1_FIRST_SPIN_VALUE){ + opt->js0_btn_rotate = spin->cur_value - 1; + opt->js1_btn_rotate = -1; + opt->js2_btn_rotate = -1; + } + else if(spin->cur_value < JS2_FIRST_SPIN_VALUE) + { + opt->js0_btn_rotate = -1; + opt->js1_btn_rotate = spin->cur_value - JS1_FIRST_SPIN_VALUE - 2; + opt->js2_btn_rotate = -1; + } + else if(spin->cur_value <= JS2_LAST_SPIN_VALUE) + { + opt->js0_btn_rotate = -1; + opt->js1_btn_rotate = -1; + opt->js2_btn_rotate = spin->cur_value - JS2_FIRST_SPIN_VALUE - 2; + } + } + break; - if(True) - { - int on; - sar_menu_spin_struct *btn_num_spin = SARMenuOptionsGetSpinByID( - m, SAR_MENU_ID_OPT_JS0_BUTTON_NUMBER, &on - ); - if(btn_num_spin != NULL) + case SAR_MENU_ID_OPT_AIR_BRAKES_BUTTON: + if(spin->cur_value == 0){ + opt->js0_btn_air_brakes = -1; + opt->js1_btn_air_brakes = -1; + opt->js2_btn_air_brakes = -1; + } + else{ + /* Set option value */ + if(spin->cur_value < JS1_FIRST_SPIN_VALUE){ + opt->js0_btn_air_brakes = spin->cur_value - 1; + opt->js1_btn_air_brakes = -1; + opt->js2_btn_air_brakes = -1; + } + else if(spin->cur_value < JS2_FIRST_SPIN_VALUE) { - int value_num = SARGetJSButtonFromButtonRoleSpin( - core_ptr, - spin, SAR_MENU_ID_OPT_JS0_BUTTON_ACTION - ) + 1; - if(value_num >= btn_num_spin->total_values) - value_num = 0; - SARMenuSpinSelectValueIndex( - display, m, on, value_num, True - ); + opt->js0_btn_air_brakes = -1; + opt->js1_btn_air_brakes = spin->cur_value - JS1_FIRST_SPIN_VALUE - 2; + opt->js2_btn_air_brakes = -1; + } + else if(spin->cur_value <= JS2_LAST_SPIN_VALUE) + { + opt->js0_btn_air_brakes = -1; + opt->js1_btn_air_brakes = -1; + opt->js2_btn_air_brakes = spin->cur_value - JS2_FIRST_SPIN_VALUE - 2; } } break; - case SAR_MENU_ID_OPT_JS0_BUTTON_NUMBER: - if(True) - { - sar_option_struct *opt = &core_ptr->option; - sar_menu_spin_struct *btn_role_spin = SARMenuOptionsGetSpinByID( - m, SAR_MENU_ID_OPT_JS0_BUTTON_ACTION, NULL + case SAR_MENU_ID_OPT_WHEEL_BRAKES_BUTTON: + if(spin->cur_value == 0){ + opt->js0_btn_wheel_brakes = -1; + opt->js1_btn_wheel_brakes = -1; + opt->js2_btn_wheel_brakes = -1; + } + else{ + /* As Wheel Brake function is mapped to a button, force Wheel + * Brakes axes spin values to "None". + */ + + int spin_num; + /* Get Left Brake axis spin object number on menu page */ + SARMenuGetObjectByID( + m, SAR_MENU_ID_OPT_BRAKE_LEFT_AXIS, &spin_num ); - if(btn_role_spin != NULL) + /* Set Left Brake spin value to 0 */ + SARMenuSpinSelectValueIndex( + display, m, spin_num, 0, True + ); + /* Get Right Brake axis spin object number on menu page */ + SARMenuGetObjectByID( + m, SAR_MENU_ID_OPT_BRAKE_RIGHT_AXIS, &spin_num + ); + /* Set Right Brake spin value to 0 */ + SARMenuSpinSelectValueIndex( + display, m, spin_num, 0, True + ); + + /* Set option value */ + if(spin->cur_value < JS1_FIRST_SPIN_VALUE){ + opt->js0_btn_wheel_brakes = spin->cur_value - 1; + opt->js1_btn_wheel_brakes = -1; + opt->js2_btn_wheel_brakes = -1; + } + else if(spin->cur_value < JS2_FIRST_SPIN_VALUE) + { + opt->js0_btn_wheel_brakes = -1; + opt->js1_btn_wheel_brakes = spin->cur_value - JS1_FIRST_SPIN_VALUE - 2; + opt->js2_btn_wheel_brakes = -1; + } + else if(spin->cur_value <= JS2_LAST_SPIN_VALUE) { - int new_val = spin->cur_value - 1; + opt->js0_btn_wheel_brakes = -1; + opt->js1_btn_wheel_brakes = -1; + opt->js2_btn_wheel_brakes = spin->cur_value - JS2_FIRST_SPIN_VALUE - 2; + } + } + break; - /* Set option for button mapping based on which value - * the action spin is on. - */ - switch(btn_role_spin->cur_value) - { - case 0: /* Rotate Modifier */ - opt->js0_btn_rotate = new_val; - break; - case 1: /* Air Brakes */ - opt->js0_btn_air_brakes = new_val; - break; - case 2: /* Wheel Brakes */ - opt->js0_btn_wheel_brakes = new_val; - break; - case 3: /* Zoom In */ - opt->js0_btn_zoom_in = new_val; - break; - case 4: /* Zoom out */ - opt->js0_btn_zoom_out = new_val; - break; - case 5: /* Hoist Up */ - opt->js0_btn_hoist_up = new_val; - break; - case 6: /* Hoist Down */ - opt->js0_btn_hoist_down = new_val; - break; -/* When adding new button mappings, be sure to add support for them - * in SARGetJSButtonFromButtonRoleSpin(). - * - * Also remember to add support for EACH joystick! - */ - } + case SAR_MENU_ID_OPT_ZOOM_IN_BUTTON: + if(spin->cur_value == 0){ + opt->js0_btn_zoom_in = -1; + opt->js1_btn_zoom_in = -1; + opt->js2_btn_zoom_in = -1; + } + else{ + /* Set option value */ + if(spin->cur_value < JS1_FIRST_SPIN_VALUE){ + opt->js0_btn_zoom_in = spin->cur_value - 1; + opt->js1_btn_zoom_in = -1; + opt->js2_btn_zoom_in = -1; + } + else if(spin->cur_value < JS2_FIRST_SPIN_VALUE) + { + opt->js0_btn_zoom_in = -1; + opt->js1_btn_zoom_in = spin->cur_value - JS1_FIRST_SPIN_VALUE - 2; + opt->js2_btn_zoom_in = -1; + } + else if(spin->cur_value <= JS2_LAST_SPIN_VALUE) + { + opt->js0_btn_zoom_in = -1; + opt->js1_btn_zoom_in = -1; + opt->js2_btn_zoom_in = spin->cur_value - JS2_FIRST_SPIN_VALUE - 2; } } - /* Update joystick button mappings from global options - * values to the gctl structure on the core structure. - * No reinitialization will take place. - */ - SARMenuOptionsJoystickButtonsRemap(core_ptr); break; - case SAR_MENU_ID_OPT_JS1_BUTTON_ACTION: - if(True) - { - int on; - sar_menu_spin_struct *btn_num_spin = SARMenuOptionsGetSpinByID( - m, SAR_MENU_ID_OPT_JS1_BUTTON_NUMBER, &on - ); - if(btn_num_spin != NULL) + case SAR_MENU_ID_OPT_ZOOM_OUT_BUTTON: + if(spin->cur_value == 0){ + opt->js0_btn_zoom_out = -1; + opt->js1_btn_zoom_out = -1; + opt->js2_btn_zoom_out = -1; + } + else{ + /* Set option value */ + if(spin->cur_value < JS1_FIRST_SPIN_VALUE){ + opt->js0_btn_zoom_out = spin->cur_value - 1; + opt->js1_btn_zoom_out = -1; + opt->js2_btn_zoom_out = -1; + } + else if(spin->cur_value < JS2_FIRST_SPIN_VALUE) { - int value_num = SARGetJSButtonFromButtonRoleSpin( - core_ptr, - spin, SAR_MENU_ID_OPT_JS1_BUTTON_ACTION - ) + 1; - if(value_num >= btn_num_spin->total_values) - value_num = 0; - SARMenuSpinSelectValueIndex( - display, m, on, value_num, True - ); + opt->js0_btn_zoom_out = -1; + opt->js1_btn_zoom_out = spin->cur_value - JS1_FIRST_SPIN_VALUE - 2; + opt->js2_btn_zoom_out = -1; + } + else if(spin->cur_value <= JS2_LAST_SPIN_VALUE) + { + opt->js0_btn_zoom_out = -1; + opt->js1_btn_zoom_out = -1; + opt->js2_btn_zoom_out = spin->cur_value - JS2_FIRST_SPIN_VALUE - 2; } } break; - case SAR_MENU_ID_OPT_JS1_BUTTON_NUMBER: - if(True) - { - sar_option_struct *opt = &core_ptr->option; - sar_menu_spin_struct *btn_role_spin = SARMenuOptionsGetSpinByID( - m, SAR_MENU_ID_OPT_JS1_BUTTON_ACTION, NULL - ); - if(btn_role_spin != NULL) + case SAR_MENU_ID_OPT_HOIST_UP_BUTTON: + if(spin->cur_value == 0){ + opt->js0_btn_hoist_up = -1; + opt->js1_btn_hoist_up = -1; + opt->js2_btn_hoist_up = -1; + } + else{ + /* Set option value */ + if(spin->cur_value < JS1_FIRST_SPIN_VALUE){ + opt->js0_btn_hoist_up = spin->cur_value - 1; + opt->js1_btn_hoist_up = -1; + opt->js2_btn_hoist_up = -1; + } + else if(spin->cur_value < JS2_FIRST_SPIN_VALUE) { - int new_val = spin->cur_value - 1; + opt->js0_btn_hoist_up = -1; + opt->js1_btn_hoist_up = spin->cur_value - JS1_FIRST_SPIN_VALUE - 2; + opt->js2_btn_hoist_up = -1; + } + else if(spin->cur_value <= JS2_LAST_SPIN_VALUE) + { + opt->js0_btn_hoist_up = -1; + opt->js1_btn_hoist_up = -1; + opt->js2_btn_hoist_up = spin->cur_value - JS2_FIRST_SPIN_VALUE - 2; + } + } + break; - /* Set option for button mapping based on which value - * the action spin is on. - */ - switch(btn_role_spin->cur_value) - { - case 0: /* Rotate Modifier */ - opt->js1_btn_rotate = new_val; - break; - case 1: /* Air Brakes */ - opt->js1_btn_air_brakes = new_val; - break; - case 2: /* Wheel Brakes */ - opt->js1_btn_wheel_brakes = new_val; - break; - case 3: /* Zoom In */ - opt->js1_btn_zoom_in = new_val; - break; - case 4: /* Zoom out */ - opt->js1_btn_zoom_out = new_val; - break; - case 5: /* Hoist Up */ - opt->js1_btn_hoist_up = new_val; - break; - case 6: /* Hoist Down */ - opt->js1_btn_hoist_down = new_val; - break; -/* When adding new button mappings, be sure to add support for them - * in SARGetJSButtonFromButtonRoleSpin(). - * - * Also remember to add support for EACH joystick! - */ - } + case SAR_MENU_ID_OPT_HOIST_DOWN_BUTTON: + if(spin->cur_value == 0){ + opt->js0_btn_hoist_down = -1; + opt->js1_btn_hoist_down = -1; + opt->js2_btn_hoist_down = -1; + } + else{ + /* Set option value */ + if(spin->cur_value < JS1_FIRST_SPIN_VALUE){ + opt->js0_btn_hoist_down = spin->cur_value - 1; + opt->js1_btn_hoist_down = -1; + opt->js2_btn_hoist_down = -1; + } + else if(spin->cur_value < JS2_FIRST_SPIN_VALUE) + { + opt->js0_btn_hoist_down = -1; + opt->js1_btn_hoist_down = spin->cur_value - JS1_FIRST_SPIN_VALUE - 2; + opt->js2_btn_hoist_down = -1; + } + else if(spin->cur_value <= JS2_LAST_SPIN_VALUE) + { + opt->js0_btn_hoist_down = -1; + opt->js1_btn_hoist_down = -1; + opt->js2_btn_hoist_down = spin->cur_value - JS2_FIRST_SPIN_VALUE - 2; } } - /* Update joystick button mappings from global options - * values to the gctl structure on the core structure. - * No reinitialization will take place. - */ - SARMenuOptionsJoystickButtonsRemap(core_ptr); break; +#undef JS2_LAST_SPIN_VALUE +#undef JS2_FIRST_SPIN_VALUE +#undef JS1_FIRST_SPIN_VALUE + case SAR_MENU_ID_OPT_VISIBILITY_MAX: /* These values should correspond to those used to * set the values in SARBuildMenus(). @@ -2780,6 +4007,7 @@ to connect to it. To start in most cases run `starty'." \ #undef SND_OFF_AS_NEEDED } +//fprintf(stderr, "%s:%d: Exiting SARMenuOptionsSpinCB()\n", __FILE__, __LINE__); } /* diff --git a/src/sarmenuoptions.h b/src/sarmenuoptions.h index 5f3bb24..0977eec 100644 --- a/src/sarmenuoptions.h +++ b/src/sarmenuoptions.h @@ -33,6 +33,11 @@ extern void SARMenuOptionsJoystickTestDrawCB( int x_min, int y_min, int x_max, int y_max ); +extern void SARMenuOptionsJoystickReinit(sar_core_struct *core_ptr); +extern void SARMenuOptionsJoystickMappingReset(sar_core_struct *core_ptr, int gc_js_nums); +extern void SARMenuOptionsJoystickMappingPrepare(sar_core_struct *core_ptr); +extern void SARMenuOptionsJoystickMappingExit(sar_core_struct *core_ptr); + extern void SARMenuOptionsGraphicsInfoRefresh(sar_core_struct *core_ptr); extern void SARMenuOptionsSoundTest(sar_core_struct *core_ptr); extern void SARMenuOptionsSoundRefresh(sar_core_struct *core_ptr); From aff610154ce836128cc37179ccb4578af5a2eaf1 Mon Sep 17 00:00:00 2001 From: jmbaud Date: Sun, 28 Jul 2024 17:29:55 +0200 Subject: [PATCH 2/3] Don't try to update axis value or button state for unconnected joystick(s). --- src/gctl.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/gctl.c b/src/gctl.c index 1a074e8..3930487 100644 --- a/src/gctl.c +++ b/src/gctl.c @@ -549,6 +549,9 @@ void GCtlUpdate( continue; sdljoystick = gc->sdljoystick[i]; + if(sdljoystick == NULL) + continue; + /* Update defined joystick operations for this joystick. * This is to tabulate a list of functions that were * handled/controlled by any of the joystick(s) so the From d9991f0c38a9f94ea2ebad573d4058ece4fe3196 Mon Sep 17 00:00:00 2001 From: jmbau <30726620+jmbau@users.noreply.github.com> Date: Sun, 28 Jul 2024 17:56:03 +0200 Subject: [PATCH 3/3] Update gctl.c indentation error --- src/gctl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gctl.c b/src/gctl.c index 3930487..1d7a81e 100644 --- a/src/gctl.c +++ b/src/gctl.c @@ -549,7 +549,7 @@ void GCtlUpdate( continue; sdljoystick = gc->sdljoystick[i]; - if(sdljoystick == NULL) + if(sdljoystick == NULL) continue; /* Update defined joystick operations for this joystick.