/** * Copyright (C) 2003 Jeremy Booth (jeremy@newdawnsoftware.com) * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. Redistributions in binary * form must reproduce the above copyright notice, this list of conditions and * the following disclaimer in the documentation and/or other materials provided * with the distribution. * The name of the author may not be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE */ #include "eventInterfaceTypes.h" #include "EventDevice.h" #include #include #include #include #include #include #include #include "logger.h" EventDevice::EventDevice(char *deviceFileName) { char tempName[Device::MAX_NAME_LENGTH-1] = "Unknown"; int i; fd = open(deviceFileName, O_RDWR | O_NONBLOCK); if(fd<0) { char errorMessage[512]; sprintf(errorMessage, "Error opening device %s read/write, Force Feedback disabled for this device\n", deviceFileName); perror(errorMessage); fd = open(deviceFileName, O_RDONLY | O_NONBLOCK); if(fd<0) { /*char errorMessage[512]; sprintf(errorMessage, "Error opening device %s\n", deviceFileName); perror(errorMessage);*/ inited = 0; return; } } else { if(ioctl(fd, EVIOCGBIT(EV_FF, sizeof(uint8_t) * 16), ff_bitmask) < 0) { char errorMessage[512]; sprintf(errorMessage, "Error reading device %s\n", deviceFileName); perror(errorMessage); } if(getBit(FF_RUMBLE, ff_bitmask)==1) { ffSupported = 1; //LOG_TRACE("Force feedback supported for %s\n", deviceFileName); int n_effects = 0; if (ioctl(fd, EVIOCGEFFECTS, &n_effects) == -1) { char errorMessage[512]; sprintf(errorMessage, "Failed to get number of effects for device %s\n", deviceFileName); perror(errorMessage); } LOG_TRACE("Device %s supports %d simultanious effects\n", deviceFileName, n_effects); effect_playing = false; effect.type=FF_RUMBLE; effect.id=-1; effect.u.rumble.strong_magnitude = (int)(0x8000); effect.u.rumble.weak_magnitude = (int)(0xc000); effect.replay.length = 5000; effect.replay.delay = 0; LOG_TRACE("Uploading effect %d\n", effect.id); if (ioctl(fd, EVIOCSFF, &effect) == -1) { perror("Upload effect"); } LOG_TRACE("Uploaded effect %d\n", effect.id); } else { ffSupported = 0; LOG_TRACE("Force feedback not supported for %s %d\n", deviceFileName, getBit(FF_RUMBLE, ff_bitmask)); } } if(ioctl(fd, EVIOCGNAME(sizeof(tempName)), tempName) < 0) { char errorMessage[512]; sprintf(errorMessage, "Error reading device %s\n", deviceFileName); perror(errorMessage); } int namelength=strlen(tempName); name = (char *)malloc(namelength+1); strncpy(name,tempName, namelength+1); LOG_TRACE("Device name for device file %s is %s\n", deviceFileName, name); uint8_t evtype_bitmask[EV_MAX/8 + 1]; memset(evtype_bitmask, 0, sizeof(evtype_bitmask)); if(ioctl(fd, EVIOCGBIT(0, EV_MAX), evtype_bitmask) < 0) { char errorMessage[512]; sprintf(errorMessage, "Error reading device %s\n", deviceFileName); perror(errorMessage); } struct input_devinfo deviceInfo; if(ioctl(fd, EVIOCGID, &deviceInfo) < 0) { char errorMessage[512]; sprintf(errorMessage, "Error reading device %s\n", deviceFileName); perror(errorMessage); } bustype = deviceInfo.bustype; vendor = deviceInfo.vendor; product = deviceInfo.product; version = deviceInfo.version; numButtons = -1; numAbsAxes = -1; numRelAxes = -1; if(!(getBit(EV_KEY, evtype_bitmask))) { numButtons = 0; } if(!(getBit(EV_REL, evtype_bitmask))) { numRelAxes = 0; } if(!(getBit(EV_ABS, evtype_bitmask))) { numAbsAxes = 0; } if(!getBit(EV_FF, evtype_bitmask)) { ffSupported = 0; } if(numButtons < 0) { // This device supports keys, deal with it. if(ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(key_bitmask)), key_bitmask) < 0) { char errorMessage[512]; sprintf(errorMessage, "Error reading device %s\n", deviceFileName); perror(errorMessage); } for(i=0;isupportedButtons[i]; } } /** * A return value of -1 means error, 0 means ok, but no change * a return of >0 means the data for this device has changed */ int EventDevice::poll(){ size_t read_bytes; struct input_event events[64]; int dataChanged=0; if(inited!=1) return -1; // first thing to do is reset all relative axis as mice never seem to do it int i; for(i=0;irelAxesData[i]; } for(i=0;iabsAxesData[i]; } for(i=0;ibuttonData[i]; } } int EventDevice::getAbsAxisMinimum(int axisNumber) { return abs_features[axisNumber].minimum; } int EventDevice::getAbsAxisMaximum(int axisNumber) { return abs_features[axisNumber].maximum; } int EventDevice::getAbsAxisFuzz(int axisNumber) { return abs_features[axisNumber].fuzz; } bool EventDevice::getFFEnabled() { if(ffSupported==1) { //LOG_TRACE("FF is supported for %s\n", getName()); return true; } //LOG_TRACE("FF is not supported for %s\n", getName()); return false; } void EventDevice::rumble(float force) { if(force>1) force=1; if(force<-1) force=-1; //LOG_TRACE("Rumbling at %d%%, (shh, pretend)\n", (int)(force*100)); if(effect_playing==true) { stop.type=EV_FF; stop.code = effect.id; stop.value=0; LOG_TRACE("Stopping effect %d\n", stop.code); if (write(fd, (const void*) &stop, sizeof(stop)) == -1) { perror("Failed to stop effect"); } else { effect_playing=false; } } if(force>0.666666) { effect.u.rumble.strong_magnitude = (int)(0x8000*force); effect.u.rumble.weak_magnitude = (int)(0xc000*force); } else if(force>0.3333333) { effect.u.rumble.strong_magnitude = (int)(0x8000*force); effect.u.rumble.weak_magnitude = (int)(0xc000*0); } else { effect.u.rumble.strong_magnitude = (int)(0x8000*0); effect.u.rumble.weak_magnitude = (int)(0xc000*force); } LOG_TRACE("Uploading effect %d\n", effect.id); if (ioctl(fd, EVIOCSFF, &effect) == -1) { perror("Upload effect"); } LOG_TRACE("Uploaded effect %d\n", effect.id); if(effect_playing==false && force!=0) { play.type = EV_FF; play.code=effect.id; play.value=1; LOG_TRACE("Playing effect %d\n", play.code); if (write(fd, (const void*) &play, sizeof(play)) == -1) { perror("Failed to play effect"); } else { effect_playing=true; } } } void EventDevice::cleanup() { char message[512]; sprintf(message, "Closing device %s\n", name); LOG_TRACE(message); close(fd); }