// $Id: evdev_device.cpp 3271 2007-10-01 17:24:54Z grumbel $ // // Pingus - A free Lemmings clone // Copyright (C) 2007 Ingo Ruhnke // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include #include #include #include #include #include #include #include #include "evdev_device.hpp" #define BITS_PER_LONG (sizeof(long) * 8) #define NBITS(x) ((((x)-1)/BITS_PER_LONG)+1) #define OFF(x) ((x)%BITS_PER_LONG) #define BIT(x) (1UL<> OFF(bit)) & 1) namespace Input { EvdevDevice::EvdevDevice(const std::string& filename) : device(filename) { fd = open(device.c_str(), O_RDONLY | O_NONBLOCK); if (fd == -1) { throw std::runtime_error(filename + ": " + std::string(strerror(errno))); } if (ioctl(fd, EVIOCGVERSION, &version)) { throw std::runtime_error("Error: EvdevDevice: Couldn't get version for " + filename); } if (1) { // FIXME: Some versions of linux don't have these structs, use arrays there struct input_id id; ioctl(fd, EVIOCGID, &id); printf("Input device ID: bus 0x%x vendor 0x%x product 0x%x version 0x%x\n", id.bustype, id.vendor, id.product, id.vendor); } { // Get the human readable name char c_name[256] = "unknown"; ioctl(fd, EVIOCGNAME(sizeof(c_name)), c_name); name = c_name; std::cout << "Name: " << name << std::endl; } { // Read in how many buttons the device has unsigned long bit[EV_MAX][NBITS(KEY_MAX)]; memset(bit, 0, sizeof(bit)); ioctl(fd, EVIOCGBIT(0, EV_MAX), bit[0]); for (int i = 0; i < EV_MAX; i++) { if (test_bit(i, bit[0])) { //printf(" Event type %d (%s)\n", i, events[i] ? events[i] : "?"); if (!i) continue; ioctl(fd, EVIOCGBIT(i, KEY_MAX), bit[i]); for (int j = 0; j < KEY_MAX; j++) { if (test_bit(j, bit[i])) { if (i == EV_KEY) { keys.push_back(Key(j)); } else if (i == EV_ABS) { // FIXME: Some Linuxes don't have these struct struct input_absinfo absinfo; ioctl(fd, EVIOCGABS(j), &absinfo); // FIXME: we are ignoring absinfo.fuzz and // absinfo.flat = deadzone // absinfo.fuzz = values in which range can be considered the same (jitter) absolutes.push_back(Absolute(j, absinfo.minimum, absinfo.maximum, absinfo.value)); } else if (i == EV_REL) { relatives.push_back(Relative(j)); } } } } } } } EvdevDevice::~EvdevDevice() { } void EvdevDevice::process_absolute(struct input_event& ev) { int axis_index = get_absolute_index_by_code(ev.code); if (axis_index != -1) { absolutes[axis_index].pos = ev.value; #if 0 CL_InputEvent e; e.device = CL_InputDevice(this); e.type = CL_InputEvent::axis_moved; e.id = axis_index; e.axis_pos = absolutes[axis_index].get_posf(); e.repeat_count = 0; sig_axis_move(e); #endif } } void EvdevDevice::process_relative(struct input_event& ev) { int idx = get_relative_index_by_code(ev.code); relatives[idx].pos += ev.value; for(std::vector::iterator i = relatives[idx].bindings.begin(); i != relatives[idx].bindings.end(); ++i) { if (relatives[idx].binding_axis == 0) (*i)->set_delta(Vector2f(-ev.value * 0.125f, 0)); // FIXME: make scaling and inversion configurable else if (relatives[idx].binding_axis == 1) (*i)->set_delta(Vector2f(0, -ev.value * 0.125f)); } } void EvdevDevice::process_key(struct input_event& ev) { int idx = get_key_index_by_code(ev.code); keys[idx].pressed = ev.value; for(std::vector::iterator i = keys[idx].bindings.begin(); i != keys[idx].bindings.end(); ++i) { if (ev.value) (*i)->set_state(BUTTON_PRESSED); else (*i)->set_state(BUTTON_RELEASED); } #if 0 CL_InputEvent e; e.device = CL_InputDevice(this); e.id = button_index; e.repeat_count = 0; if (ev.value) { e.type = CL_InputEvent::pressed; sig_key_down(e); } else { e.type = CL_InputEvent::released; sig_key_up(e); } #endif } int EvdevDevice::get_relative_index_by_code(int code) { for(std::vector::size_type i = 0; i != relatives.size(); ++i) if (relatives[i].code == code) return i; return -1; } int EvdevDevice::get_key_index_by_code(int code) { for(std::vector::size_type i = 0; i != keys.size(); ++i) if (keys[i].code == code) return i; return -1; } int EvdevDevice::get_absolute_index_by_code(int code) { for(std::vector::size_type i = 0; i != absolutes.size(); ++i) if (absolutes[i].code == code) return i; return -1; } void EvdevDevice::update(float delta) { struct input_event ev[128]; // FIXME: turn this into a while loop so all events get processed int rd = read(fd, ev, sizeof(struct input_event) * 128); //std::cout << rd / sizeof(struct input_event) << std::endl; if (rd >= (int) sizeof(struct input_event)) { for (int i = 0; i < rd / (int)sizeof(struct input_event); ++i) { //std::cout << ev[i].type << " " << ev[i].code << " " << ev[i].value << std::endl; switch (ev[i].type) { case EV_ABS: process_absolute(ev[i]); break; case EV_REL: process_relative(ev[i]); break; case EV_KEY: process_key(ev[i]); break; default: #if 0 if (ev[i].type == EV_SYN) { printf("Event: time %ld.%06ld, -------------- %s ------------\n", ev[i].time.tv_sec, ev[i].time.tv_usec, ev[i].code ? "Config Sync" : "Report Sync" ); } else if (ev[i].type == EV_MSC && (ev[i].code == MSC_RAW || ev[i].code == MSC_SCAN)) { printf("Event: time %ld.%06ld, type %d (%s), code %d (%s), value %02x\n", ev[i].time.tv_sec, ev[i].time.tv_usec, ev[i].type, events[ev[i].type] ? events[ev[i].type] : "?", ev[i].code, names[ev[i].type] ? (names[ev[i].type][ev[i].code] ? names[ev[i].type][ev[i].code] : "?") : "?", ev[i].value); } else { printf("Event: time %ld.%06ld, type %d (%s), code %d (%s), value %d\n", ev[i].time.tv_sec, ev[i].time.tv_usec, ev[i].type, events[ev[i].type] ? events[ev[i].type] : "?", ev[i].code, names[ev[i].type] ? (names[ev[i].type][ev[i].code] ? names[ev[i].type][ev[i].code] : "?") : "?", ev[i].value); } #endif break; } } } } Scroller* EvdevDevice::create_scroller(Control* parent, int x, int y) { Scroller* scroller = new Scroller(parent); bool have_x = false; bool have_y = false; for(std::vector::size_type i = 0; i != relatives.size(); ++i) { if (relatives[i].code == x) { relatives[i].binding_axis = 0; relatives[i].bindings.push_back(scroller); have_x = true; } else if (relatives[i].code == y) { relatives[i].binding_axis = 1; relatives[i].bindings.push_back(scroller); have_y = true; } } if (have_x && have_y) { return scroller; } else { delete scroller; std::cout << "EvdevDevice: " << device << " doesn't have x or y: x=" << x << " y=" << y << std::endl; return 0; } } Button* EvdevDevice::create_button(Control* parent, int id) { for(std::vector::size_type i = 0; i != keys.size(); ++i) if (keys[i].code == id) { Button* button = new Button(parent); keys[i].bindings.push_back(button); return button; } std::cout << "EvdevDevice: " << device << " doesn't have button " << id << std::endl; return 0; } } // namespace Input #ifdef __TEST__ // g++ -D__TEST__ evdev_device.cpp -o evdev -Wall -Werror int main(int argc, char** argv) { if (argc != 2) { std::cout << "Usage: evdev FILENAME" << std::endl; } else { std::cout << "EvdevDevice: " << argv[1] << std::endl; Input::EvdevDevice dev(argv[1]); while(true) { dev.update(0.0f); } } return 0; } #endif /* EOF */