//////////////////////////////////////////////////////////// // input.cpp // // Input device classes for EDrive, a multiplatform driving simulator. // // Copyright 2004 by Evan Alexander Weaver // // Despite the copyright, this is free software. See edrive.cpp for details. // // Date last modified: 31 May 2004 #include "platform.h" #if ED_DIRECTX_9_INPUT //*************************************************** #define INITGUID #include #include #include // "safe" Release of COM object #define RELEASE(x) if (x) { x->Release(); x = NULL; } // Global variables shared by all input devices. Yuck. // static LPDIRECTINPUT8 Di = NULL; // The DirectInput device static int Didevcount = 0; // how many input devices are using Di #else //******************************************************************** #include #include #include #include #include #endif //******************************************************************* #include #include "error.h" #include "input.h" // Clean up after all input devices are gone // void shutdowninput() { #if ED_DIRECTX_9_INPUT //*********************************************** RELEASE(Di) #endif //*************************************************************** } /////////////////////////////////////////////////////////////////////////// // keyboard class // // The use of a static variable to keep track of the keystrokes (necessitated // by GLUT's method of installing the keyboard callbacks) means that there // had better be only one instance of this class. No attempt has been made // to make sure you don't make two instances, however, so be careful. // Key state values for the keyboard. Note that we only track the keys // we are interested in, and there is only room for 32 of these. // unsigned int keyboard::keys = 0; #if ED_OPENGL_GLUT //******************************************************* // keyboard callbacks for GLUT // handle ASCII keys presses // void asciikeys(unsigned char c, int x, int y) { switch (c) { case 'a': case 'A': keyboard::keys |= EDKEY_A; break; case 'z': case 'Z': keyboard::keys |= EDKEY_Z; break; case 'c': case 'C': keyboard::keys |= EDKEY_C; break; case 10: case 13: keyboard::keys |= EDKEY_ENTER; break; case 27: keyboard::keys |= EDKEY_ESC; break; } } // handle ASCII key releases // void asciikeysup(unsigned char c, int x, int y) { switch (c) { case 'a': case 'A': keyboard::keys &= ~EDKEY_A; break; case 'z': case 'Z': keyboard::keys &= ~EDKEY_Z; break; case 'c': case 'C': keyboard::keys &= ~EDKEY_C; break; case 10: case 13: keyboard::keys &= ~EDKEY_ENTER; break; case 27: keyboard::keys &= ~EDKEY_ESC; break; } } // handle non-ASCII key presses // void nonasciikeys(int c, int x, int y) { switch (c) { case GLUT_KEY_UP: keyboard::keys |= EDKEY_UP; break; case GLUT_KEY_DOWN: keyboard::keys |= EDKEY_DOWN; break; case GLUT_KEY_LEFT: keyboard::keys |= EDKEY_LEFT; break; case GLUT_KEY_RIGHT: keyboard::keys |= EDKEY_RIGHT; break; } } // handle non-ASCII key releases // void nonasciikeysup(int c, int x, int y) { switch (c) { case GLUT_KEY_UP: keyboard::keys &= ~EDKEY_UP; break; case GLUT_KEY_DOWN: keyboard::keys &= ~EDKEY_DOWN; break; case GLUT_KEY_LEFT: keyboard::keys &= ~EDKEY_LEFT; break; case GLUT_KEY_RIGHT: keyboard::keys &= ~EDKEY_RIGHT; break; } } #endif //******************************************************************* // Default keyboard is not attached to anything, since the necessary // resources to create it may not be available yet. // keyboard::keyboard() { #if ED_DIRECTX_9_INPUT //*********************************************** dev = NULL; Didevcount++; #endif //*************************************************************** keys = 0; } // Unattach keyboard and maybe shut down all input // keyboard::~keyboard() { destroy(); #if ED_DIRECTX_9_INPUT //*********************************************** if (0 == --Didevcount) shutdowninput(); #endif //*************************************************************** } // Unattach keyboard // void keyboard::destroy() { #if ED_DIRECTX_9_INPUT //*********************************************** if (dev) { dev->Unacquire(); RELEASE(dev) } #endif //*************************************************************** } // Try to reaccess keyboard after we've lost it for some reason // void keyboard::restore() { #if ED_DIRECTX_9_INPUT //*********************************************** if (dev) dev->Acquire(); #endif //*************************************************************** } // Attach the object to the physical keyboard // #if ED_DIRECTX_9_INPUT //*************************************************** bool keyboard::create(HINSTANCE hinst, HWND hwnd) #else //******************************************************************** bool keyboard::create() #endif //******************************************************************* { bool rc = true; #if ED_DIRECTX_9_INPUT //*********************************************** // Make the DirectInput8 object if necessary, then create the // keyboard device and set its data format and cooperative level // before attempting to acquire it. // if (dev == NULL && (Di != NULL || SUCCEEDED(DirectInput8Create(hinst, DIRECTINPUT_VERSION, IID_IDirectInput8, (void **)&Di, NULL)))) { if (FAILED(Di->CreateDevice(GUID_SysKeyboard, &dev, NULL))) rc = false; else if (FAILED(dev->SetDataFormat(&c_dfDIKeyboard)) || FAILED(dev->SetCooperativeLevel(hwnd, DISCL_FOREGROUND | DISCL_NONEXCLUSIVE)) || FAILED(dev->Acquire())) { dev->Release(); dev = NULL; rc = false; } } else { error("Failed to make DirectInput8 object"); rc = false; } #else //**************************************************************** // Install GLUT keyboard callbacks glutKeyboardFunc(asciikeys); glutKeyboardUpFunc(asciikeysup); glutSpecialFunc(nonasciikeys); glutSpecialUpFunc(nonasciikeysup); // Turn off key repeating glutIgnoreKeyRepeat(1); #endif //*************************************************************** return rc; } // Return the current state of the keys of interest on the keyboard (one // bit per key, 1 means pressed and 0 means released) // unsigned int keyboard::read() { #if ED_DIRECTX_9_INPUT //*********************************************** unsigned int rc = 0; char keys[256]; HRESULT stat; if (dev) { // Polling the keyboard isn't necessary on all machines, // but it doesn't hurt and is very fast if unnecessary. // dev->Poll(); // may not be necessary, but doesn't hurt // If we've lost the keyboard in the meantime, try to // get it back. // if (DIERR_INPUTLOST == (stat = dev->GetDeviceState(sizeof keys, keys))) { if (SUCCEEDED(dev->Acquire())) stat = dev->GetDeviceState(sizeof keys, keys); } // turn on the necessary bits of the return value // if (SUCCEEDED(stat)) rc = (keys[DIK_ESCAPE] & 0x80 ? EDKEY_ESC : 0) | (keys[DIK_UP] & 0x80 ? EDKEY_UP : 0) | (keys[DIK_DOWN] & 0x80 ? EDKEY_DOWN : 0) | (keys[DIK_LEFT] & 0x80 ? EDKEY_LEFT : 0) | (keys[DIK_RIGHT] & 0x80 ? EDKEY_RIGHT : 0) | (keys[DIK_A] & 0x80 ? EDKEY_A : 0) | (keys[DIK_C] & 0x80 ? EDKEY_C : 0) | (keys[DIK_Z] & 0x80 ? EDKEY_Z : 0) | (keys[DIK_RETURN] & 0x80 ? EDKEY_ENTER : 0); } return rc; #else //**************************************************************** return keys; #endif //*************************************************************** } ////////////////////////////////////////////////////////////////////////// // joystickid class // // The ID for a joystick. In DirectInput, this is a GUID, but in Linux it // is a string (with the file name of the joystick device). We need to be // able to remember what joystick was chosen, so this class was made in order // to have the game configuration code (etc.) not be system dependent. // // Default joystickid is "empty". // joystickid::joystickid() { #if ED_DIRECTX_9_INPUT //*********************************************** id = GUID_NULL; #else //**************************************************************** id[0] = '\0'; #endif //*************************************************************** } // In a moment of weakness, a whole bunch of one-liners that are system // dependent. They were written in one big #if/#else rather than separately // out of laziness. // #if ED_DIRECTX_9_INPUT //*************************************************** // Make a joystickid from a joystick GUID // joystickid::joystickid(const GUID &guid) { id = guid; } // Make a GUID from a joystickid // joystickid::operator GUID() const { return id; } // Read a joystickid from an open file, returning true if successful // bool joystickid::fread(FILE *fp) { return 1 == ::fread(&id, sizeof id, 1, fp); } // Write a joystickid to an open file, returning true if successful // bool joystickid::fwrite(FILE *fp) const { return 1 == ::fwrite(&id, sizeof id, 1, fp); } // Return true if the joystick ID is "empty" // bool joystickid::empty() const { return id == GUID_NULL; } // Return true if two joystickids are equal // bool joystickid::operator==(const joystickid &x) const { return id == x.id; } #else //******************************************************************** // Make a joystickid from a device name // joystickid::joystickid(const char *s) { strncpy(id, s, (sizeof id) - 1); id[(sizeof id) - 1] = '\0'; } // Make a device name from a joystickid // joystickid::operator const char *() const { return id; } // Read a joystickid from an open file, returning true if successful // bool joystickid::fread(FILE *fp) { return 1 == ::fread(id, sizeof id, 1, fp); } // Write a joystickid to an open file, returning true if successful // bool joystickid::fwrite(FILE *fp) const { return 1 == ::fwrite(id, sizeof id, 1, fp); } // Return true if the joystick ID is "empty" // bool joystickid::empty() const { return id[0] == '\0'; } // Return true if two joystickids are equal // bool joystickid::operator==(const joystickid &x) const { return 0 == strcmp(id, x.id); } #endif //******************************************************************* ////////////////////////////////////////////////////////////////////////// // joysticklist class // // Used to list the available joysticks. // #if ED_DIRECTX_9_INPUT //*************************************************** // Callback function used in the enumeration of joystick devices // The second parameter, formally an LPVOID, is declared as a // joysticklist* to save the effort of casting. This function simply // adds each joystick to the joysticklist. // BOOL CALLBACK enumjoysticks(LPDIDEVICEINSTANCE di, joysticklist *pjsl) { pjsl->add(di->guidInstance, di->tszInstanceName); return DIENUM_CONTINUE; } #else //******************************************************************** // The possible joystick devices. Note that it is possible on some // systems that these may not be the only choices. // char joysticklist::choices[4][20] = { "/dev/js0", "/dev/js1", "/dev/js2", "/dev/js3" }; #endif //******************************************************************* // Default joysticklist is empty // joysticklist::joysticklist() { joycnt = 0; names[0][0] = '\0'; } // (Re)fill the joysticklist. If a joystick has been attached since the // program was started, it should show up on the list after a refresh. // #if ED_DIRECTX_9_INPUT //*************************************************** void joysticklist::refresh(HINSTANCE hinst) #else //******************************************************************** void joysticklist::refresh() #endif //******************************************************************* { joycnt = 0; #if ED_DIRECTX_9_INPUT //*********************************************** // create the DirectInput8 device if necessary, then enumerate // the joysticks, adding them to this instance. Note that this // object doesn't worry about getting rid of the the DirectInput8 // object, assuming that something else (the keyboard at least) // will take care of that. // if (Di != NULL || SUCCEEDED(DirectInput8Create(hinst, DIRECTINPUT_VERSION, IID_IDirectInput8, (void **)&Di, NULL))) Di->EnumDevices(DI8DEVCLASS_GAMECTRL, (LPDIENUMDEVICESCALLBACK)enumjoysticks, this, DIEDFL_ATTACHEDONLY); #else //**************************************************************** // try each possible joystick in turn // int fd; for (int i = 0; i < 4; i++) { // try to open it if (-1 != (fd = open(choices[i], O_RDONLY))) { names[i][0] = '\0'; // Got one, so try to get its name ioctl(fd, JSIOCGNAME(sizeof names[i]), names[i]); if (names[i][0] != '\0') { ids[joycnt++] = i; } else errorf("Opened joystick %s, but there is no name", choices[i]); close(fd); } } #endif //*************************************************************** } // Return the number of available joysticks, assuming refresh has already // been called. // int joysticklist::count() const { return joycnt; } // Return the joystickid of the "i"th available joystick // joystickid joysticklist::getid(int i) const { #if ED_DIRECTX_9_INPUT //*********************************************** return ids[(i<0 || joycnt==0) ? 0 : i>=joycnt ? joycnt-1 : i]; #else //**************************************************************** return (0 <= i && i < joycnt) ? choices[ids[i]] : ""; #endif //*************************************************************** } // Add a joystick (ID and name) to the list (DirectX only) // #if ED_DIRECTX_9_INPUT //*************************************************** void joysticklist::add(joystickid id, const char *name) { if (joycnt < 15) { ids[joycnt] = id; strcpy(names[joycnt++], name); } } #endif //******************************************************************* // Return the "friendly" name for the "i"th joystick. // const char *joysticklist::getdesc(int i) { #if ED_DIRECTX_9_INPUT //*********************************************** return names[(i < 0 || joycnt == 0) ? 0 : i >= joycnt ? joycnt - 1 : i]; #else //**************************************************************** return (0 <= i && i < joycnt) ? names[ids[i]] : ""; #endif //*************************************************************** } /////////////////////////////////////////////////////////////////////////// // joystick class // // A joystick. Currently, force feedback and button presses are not used #if ED_DIRECTX_9_INPUT //*************************************************** // List of offsets (in the DIJOYSTATE2 structure) of all the possible axes. // DWORD joystick::axofs[6] = {DIJOFS_X, DIJOFS_Y, DIJOFS_Z, DIJOFS_RX, DIJOFS_RY, DIJOFS_RZ}; // Callback function used when enumerating the axes on a joystick. // The array passed is an array of ints indicating if the axis exists // or not (position 0 is x axis, position 1 is y, and position 2 is z). // This function assumes they are all initialized to 0 before enumeration. // BOOL CALLBACK enumaxes(LPCDIDEVICEOBJECTINSTANCE dodesc, bool axes[]) { if (dodesc->guidType == GUID_XAxis) axes[0] = true; else if (dodesc->guidType == GUID_YAxis) axes[1] = true; else if (dodesc->guidType == GUID_ZAxis) axes[2] = true; else if (dodesc->guidType == GUID_RxAxis) axes[3] = true; else if (dodesc->guidType == GUID_RyAxis) axes[4] = true; else if (dodesc->guidType == GUID_RzAxis) axes[5] = true; return DIENUM_CONTINUE; } #endif //******************************************************************* // Default joystick is not associated with a physical device // joystick::joystick() { #if ED_DIRECTX_9_INPUT //*********************************************** dev = NULL; for (int i = 0; i < 6; i++) active[i] = false; Didevcount++; #else //**************************************************************** for (int i = 0; i < 20; i++) { axis[i] = 40000; // special value meaning "not used" button[i] = 0; } steeraxis = accelaxis = brakeaxis = 0; fd = -1; #endif //*************************************************************** } // Disassociate the joystick from a physical device (and perhaps shut down // the input subsystem) joystick::~joystick() { destroy(); #if ED_DIRECTX_9_INPUT //*********************************************** if (0 == --Didevcount) shutdowninput(); #endif //*************************************************************** } // Disassociate the joystick from a physical device void joystick::destroy() { #if ED_DIRECTX_9_INPUT //*********************************************** if (dev) { dev->Unacquire(); RELEASE(dev) for (int i = 0; i < 6; i++) active[i] = false; } #else //**************************************************************** if (fd != -1) { close(fd); fd = -1; for (int i = 0; i < 20; i++) { axis[i] = 40000; button[i] = 0; } } #endif //*************************************************************** } // Reestablish connection with the joystick if it has been lost. // void joystick::restore() { #if ED_DIRECTX_9_INPUT //*********************************************** if (dev) dev->Acquire(); #endif //*************************************************************** } // Return whether the joystick associated with a physical device or not. // bool joystick::alive() const { #if ED_DIRECTX_9_INPUT //*********************************************** return dev; #else //**************************************************************** return fd != -1; #endif //*************************************************************** } // Associate the joystick with the specified physical joystick // #if ED_DIRECTX_9_INPUT //*************************************************** bool joystick::create(const joystickid &id, HWND hwnd, HINSTANCE hinst) #else //******************************************************************** bool joystick::create(const joystickid &id) #endif //******************************************************************* { bool rc = false; #if ED_DIRECTX_9_INPUT //*********************************************** // Create the DirectInput8 object (if necessary), then create the // the joystick device, set the data format to "extended joystick", // set the cooperative level, and enumerate the available axes // if (dev == NULL && (Di != NULL || SUCCEEDED(DirectInput8Create(hinst, DIRECTINPUT_VERSION, IID_IDirectInput8, (void **)&Di, NULL))) && !id.empty() && SUCCEEDED(Di->CreateDevice(GUID(id), &dev, NULL)) && SUCCEEDED(dev->SetDataFormat(&c_dfDIJoystick2)) && SUCCEEDED(dev->SetCooperativeLevel(hwnd, DISCL_NONEXCLUSIVE | DISCL_FOREGROUND)) && SUCCEEDED(dev->EnumObjects((LPDIENUMDEVICEOBJECTSCALLBACK)enumaxes, (LPVOID)active, DIDFT_ABSAXIS))) { // Set the range, deadzone, and saturation for each axis. For // simplicity, all axes are given the same range, deadzone and // saturation point DIPROPRANGE range; // joystick range (-100 to 100) range.diph.dwSize = sizeof range; range.diph.dwHeaderSize = sizeof range.diph; range.diph.dwHow = DIPH_BYOFFSET; range.lMin = -100; range.lMax = 100; DIPROPDWORD dead, // dead zone (.5%) sat; // saturation point (99.5%) dead.diph.dwSize = sizeof dead; dead.diph.dwHeaderSize = sizeof dead.diph; dead.diph.dwHow = DIPH_BYOFFSET; dead.dwData = 50; sat = dead; sat.dwData = 9950; for (int i = 0; i < 6; i++) { if (active[i]) { range.diph.dwObj = dead.diph.dwObj = sat.diph.dwObj = axofs[i]; dev->SetProperty(DIPROP_RANGE, &range.diph); dev->SetProperty(DIPROP_DEADZONE, &dead.diph); dev->SetProperty(DIPROP_SATURATION, &sat.diph); } } // input devices need to be Acquire()d before being used. if (SUCCEEDED(dev->Acquire())) { // By default, assume X axis is for steering, Y axis // in reverse is for acceleration, and Z rotation axis // (if available) in reverse is for braking (or else // the Y axis, forward, is used for braking). This covers // a wide range of available wheels and joysticks. // steeraxis = (active[0] ? 1 : 0); accelaxis = (active[1] ? -2 : 0); brakeaxis = (active[5] ? -6 : active[1] ? 2 : 0); guid = GUID(id); rc = true; } else destroy(); } #else //**************************************************************** // By default, assume X axis is for steering, Y axis is shared // between acceleration (in reverse) and braking (forward). // Unfortunately, the joystick driver reports many wheels that have // a separate acceleration and braking axis in a strange way: the Y // axis reports both pedals together while the other axis reports // just the brake pedal. I didn't want to have to add the brake axis // back into the Y axis (since I don't know how prevalent this // behaviour is), and so made the default behaviour to use the // shared Y axis. // if (rc = -1 != (fd = open(id, O_RDONLY | O_NONBLOCK))) { steeraxis = 1; accelaxis = -2; brakeaxis = 2; } #endif //*************************************************************** return rc; } // (Private function for internal use only) Poll the joystick for its current // values, returning true if successful. // bool joystick::readdata() { bool rc = false; #if ED_DIRECTX_9_INPUT //*********************************************** HRESULT stat; if (dev) { // Polling the joystick isn't necessary on all machines, // but it doesn't hurt and is very fast if unnecessary. // dev->Poll(); // may not be necessary, but doesn't hurt // If we've lost the keyboard in the meantime, try to get // it back, then read joystick data into the "js" member. // if (DIERR_INPUTLOST == (stat = dev->GetDeviceState(sizeof js, &js))) { if (SUCCEEDED(dev->Acquire())) stat = dev->GetDeviceState(sizeof js, &js); } rc = SUCCEEDED(stat); } #else //**************************************************************** struct js_event event; if (alive()) { // process all pending joystick events, changing the states // stored in members "axis" and "button" as appropriate. // while ((sizeof event) == ::read(fd, &event, sizeof event)) { if (event.type == JS_EVENT_BUTTON && event.number < 20) button[event.number] = event.value; else if (event.type == JS_EVENT_AXIS && event.number < 20) axis[event.number] = event.value; } rc = true; } #endif //*************************************************************** return rc; } // Return the state of the steering, acceleration and braking axes through // the matching parameters. A value of 20000 means that that particular // axis is not used (so keys should be checked instead). The returned // range for steering is -100 (full left) to 100 (full right), and for // acceleration and braking is 0 (pedal not touched) to 200 (pedal to // the floor). A true value is returned if any of the axes could be read. // bool joystick::read(int &steer, int &accel, int &brake) { bool rc = false; steer = accel = brake = 20000; if (readdata()) { #if ED_DIRECTX_9_INPUT //******************************************* // Raw ranges are -100 to 100 for each physical axis if (steeraxis) if (steeraxis > 0) // right goes numerically up steer = *(LONG *)((char *)&js + axofs[steeraxis - 1]); else // right goes numerically down steer = -*(LONG *)((char *)&js + axofs[-(steeraxis + 1)]); if (accelaxis && accelaxis == -brakeaxis) { // shared acceleration/braking axis. The axis is split // at 0 and each half is reported separately (and doubled // to be in the 0-200 range). // int x; if (accelaxis > 0) { x = *(LONG *)((char *)&js + axofs[accelaxis - 1]); accel = (x > 0 ? x + x : 0); brake = (x < 0 ? - (x + x) : 0); } else { x = *(LONG *)((char *)&js + axofs[brakeaxis - 1]); brake = (x > 0 ? x + x : 0); accel = (x < 0 ? - (x + x) : 0); } } else { // separate axes for acceleration and braking // if (accelaxis) if (accelaxis > 0) accel = 100 + *(LONG *)((char *)&js + axofs[accelaxis - 1]); else accel = 100 - *(LONG *)((char *)&js + axofs[-(accelaxis + 1)]); if (brakeaxis) if (brakeaxis > 0) brake = 100 + *(LONG *)((char *)&js + axofs[brakeaxis - 1]); else brake = 100 - *(LONG *)((char *)&js + axofs[-(brakeaxis + 1)]); } #else //************************************************************ // raw axis data is in the range -32767 to 32768. Note how // dividing by 327 essentially makes +/-32700 the saturation // point. if (steeraxis) if (steeraxis > 0) steer = axis[steeraxis - 1]/327; else steer = -axis[-(steeraxis + 1)]/327; if (accelaxis && accelaxis == -brakeaxis) { // shared acceleration/braking axis // int x; if (accelaxis > 0) { x = axis[accelaxis - 1]/327; accel = (x > 0 ? x + x : 0); brake = (x < 0 ? -(x + x) : 0); } else { x = axis[brakeaxis - 1]/327; brake = (x > 0 ? x + x : 0); accel = (x < 0 ? -(x + x) : 0); } } else { // separate acceleration/braking axes if (accelaxis) if (accelaxis > 0) accel = (32767 + axis[accelaxis - 1]) / 327; else accel = (32767 - axis[-(accelaxis + 1)]) / 327; if (brakeaxis) if (brakeaxis > 0) brake = (32767 + axis[brakeaxis - 1]) / 327; else brake = (32767 - axis[-(brakeaxis + 1)]) / 327; } #endif //*********************************************************** rc = true; } return rc; } // Return ID of axis selected by moving the joystick, or zero if // the joystick hasn't been moved enough yet. If "reset" is true // then the starting position is reset to the current joystick position and // zero is returned. In order to let the user pick an axis by moving it, // first call this function with a true parameter, then call it repeatedly // with a false parameter until it returns a non-zero value. The ID // returned is dir * (1 + index of axis), where dir is -1 or 1 depending // on the direction of travel reported, or zero if no axis has been moved // far enough yet to justify its selection. // // Note that because static variables are used for the storage of axis // values during the selection, you should not try to pick an axis on more // than one joystick at a time. // int joystick::pickaxis(bool reset) { int rc = 0, i, n; bool keeptrying; // joystick settings stored during the "picking" process // #if ED_DIRECTX_9_INPUT //*********************************************** static DIJOYSTATE2 js1; #else //**************************************************************** static int axis1[20]; #endif //*************************************************************** if (reset) { // reset the stored settings to the current state of the joystick // readdata(); #if ED_DIRECTX_9_INPUT //******************************************* memcpy(&js1, &js, sizeof js); #else //************************************************************ for (i = 0; i < 20; i++) { axis1[i] = axis[i]; } #endif //*********************************************************** } else { // look for significant movement in any axis since the last reset // #if ED_DIRECTX_9_INPUT //******************************************* // look for movement of 50 (out of a possible 200) // if (readdata()) { for (i = 0, keeptrying = true; keeptrying && i < 6; i++) { if (active[i]) { n = *(LONG *)((char *)&js + axofs[i]) - *(LONG *)((char *)&js1 + axofs[i]); if (n > 50) { rc = i + 1; keeptrying = false; } else if (n < -50) { rc = -(i + 1); keeptrying = false; } } } } #else //************************************************************ // look for movement of 12000 (out of a possible 65536) // for (i = 0, keeptrying = readdata(); i < 20 && keeptrying; i++) { n = axis[i] - axis1[i]; if (n > 12000) { rc = i + 1; keeptrying = false; } else if (n < -12000) { rc = -(i + 1); keeptrying = false; } } #endif //*********************************************************** } return rc; } // Set the steering, acceleration and braking axes to the specified values. // The values are dir * (1 + index of physical axis) where dir is 1 or -1 // depending on the direction of travel reported. A value of 0 means // that that particular axis is not controlled by the joystick. // void joystick::setaxes(int stax, int acax, int brax) { #if ED_DIRECTX_9_INPUT //*********************************************** steeraxis = ((0 < stax && stax <= 6 && active[stax - 1]) || (-6 <= stax && stax < 0 && active[-(stax + 1)])) ? stax:0; accelaxis = ((0 < acax && acax <= 6 && active[acax - 1]) || (-6 <= acax && acax < 0 && active[-(acax + 1)])) ? acax:0; brakeaxis = ((0 < brax && brax <= 6 && active[brax - 1]) || (-6 <= brax && brax < 0 && active[-(brax + 1)])) ? brax:0; #else //**************************************************************** steeraxis = (-20 < stax && stax < 20 ? stax : 0); accelaxis = (-20 < acax && acax < 20 ? acax : 0); brakeaxis = (-20 < brax && brax < 20 ? brax : 0); #endif //*************************************************************** }