/* [<][>][^][v][top][bottom][index][help] */
DEFINITIONS
This source file includes following definitions.
- init
- init
- check
- scancode_to_gnash_key
- scanForDevices
//
// Copyright (C) 2010, 2011 Free Software Foundation, Inc
//
// 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 3 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
//
#ifdef HAVE_CONFIG_H
#include "gnashconfig.h"
#endif
#include "log.h"
#include "InputDevice.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <linux/input.h>
#include <linux/kd.h>
namespace gnash {
static const char *INPUT_DEVICE = "/dev/input/event0";
EventDevice::EventDevice()
{
// GNASH_REPORT_FUNCTION;
}
EventDevice::EventDevice(Gui *gui)
{
// GNASH_REPORT_FUNCTION;
_gui = gui;
}
bool
EventDevice::init()
{
GNASH_REPORT_FUNCTION;
return init(INPUT_DEVICE, DEFAULT_BUFFER_SIZE);
}
bool
EventDevice::init(const std::string &filespec, size_t /* size */)
{
GNASH_REPORT_FUNCTION;
_filespec = filespec;
// Try to open mouse device, be error tolerant (FD is kept open all the time)
_fd = open(filespec.c_str(), O_RDONLY);
if (_fd < 0) {
log_debug(_("Could not open %s: %s"), filespec.c_str(), strerror(errno));
return false;
}
if (fcntl(_fd, F_SETFL, fcntl(_fd, F_GETFL) | O_NONBLOCK) < 0) {
log_error(_("Could not set non-blocking mode for pointing device: %s"),
strerror(errno));
close(_fd);
_fd = -1;
return false;
}
// Get the version number of the input event subsystem
int version;
if (ioctl(_fd, EVIOCGVERSION, &version)) {
perror("evdev ioctl");
}
log_debug("evdev driver version is %d.%d.%d",
version >> 16, (version >> 8) & 0xff,
version & 0xff);
if(ioctl(_fd, EVIOCGID, &_device_info)) {
perror("evdev ioctl");
}
char name[256]= "Unknown";
if(ioctl(_fd, EVIOCGNAME(sizeof(name)), name) < 0) {
perror("evdev ioctl");
}
log_debug("The device on %s says its name is %s", filespec, name);
log_debug("vendor %04hx product %04hx version %04hx",
_device_info.vendor, _device_info.product,
_device_info.version);
switch (_device_info.bustype) {
case BUS_PCI:
log_unimpl("is a PCI bus type");
break;
case BUS_ISAPNP:
log_unimpl("is a PNP bus type");
break;
case BUS_USB:
// FIXME: this probably needs a better way of checking what
// device things truly are.
log_debug("is on a Universal Serial Bus");
// ID 0eef:0001 D-WAV Scientific Co., Ltd eGalax TouchScreen
if ((_device_info.product == 0x0001) && (_device_info.vendor == 0x0eef)) {
_type = InputDevice::TOUCHMOUSE;
// ID 046d:c001 Logitech, Inc. N48/M-BB48 [FirstMouse Plus]
} else if ((_device_info.product == 0xc001) && (_device_info.vendor == 0x046d)) {
_type = InputDevice::MOUSE;
// ID 0001:0001 AT Translated Set 2 keyboard
} else if ((_device_info.product == 0x0001) && (_device_info.vendor == 0x0001)) {
_type = InputDevice::MOUSE;
// ID 067b:2303 Prolific Technology, Inc. PL2303 Serial Port
} else if ((_device_info.product == 0x2303) && (_device_info.vendor == 0x067b)) {
_type = InputDevice::SERIALUSB ;
// ID 0471:0815 Philips (or NXP) eHome Infrared Receiver
} else if ((_device_info.product == 0x0815) && (_device_info.vendor == 0x0471)) {
_type = InputDevice::INFRARED;
}
break;
case BUS_HIL:
log_unimpl("is a HIL bus type");
break;
case BUS_BLUETOOTH:
log_unimpl("is Bluetooth bus type ");
break;
#ifdef BUS_VIRTUAL
case BUS_VIRTUAL:
log_unimpl("is a Virtual bus type ");
break;
#endif
case BUS_ISA:
log_unimpl("is an ISA bus type");
break;
case BUS_I8042:
// This is for keyboards and mice
log_debug("is an I8042 bus type");
if (strstr(name, "keyboard") != 0) {
_type = InputDevice::KEYBOARD;
} else {
if (strstr(name, "Mouse") != 0) {
_type = InputDevice::MOUSE;
}
}
break;
case BUS_XTKBD:
log_unimpl("is an XTKBD bus type");
break;
case BUS_RS232:
log_unimpl("is a serial port bus type");
break;
case BUS_GAMEPORT:
log_unimpl("is a gameport bus type");
break;
case BUS_PARPORT:
log_unimpl("is a parallel port bus type");
break;
case BUS_AMIGA:
log_unimpl("is an Amiga bus type");
break;
case BUS_ADB:
log_unimpl("is an AOB bus type");
break;
case BUS_I2C:
log_unimpl("is an i2C bus type ");
break;
case BUS_HOST:
log_debug("is Host bus type");
_type = InputDevice::POWERBUTTON;
break;
case BUS_GSC:
log_unimpl("is a GSC bus type");
break;
#ifdef BUS_ATARI
case BUS_ATARI:
log_unimpl("is an Atari bus type");
break;
#endif
default:
log_error("Unknown bus type %d!", _device_info.bustype);
}
log_debug("Event enabled for %s on fd #%d", _filespec, _fd);
return true;
}
bool
EventDevice::check()
{
GNASH_REPORT_FUNCTION;
bool activity = false;
if (_fd < 0) {
return false; // no device
}
// Try to read something from the device
boost::shared_array<boost::uint8_t> buf = readData(sizeof( struct input_event));
// time,type,code,value
if (!buf) {
return false;
}
struct input_event *ev = reinterpret_cast<struct input_event *>(buf.get());
// log_debug("Type is: %hd, Code is: %hd, Val us: %d", ev->type, ev->code,
// ev->value);
switch (ev->type) {
case EV_SYN:
log_unimpl("Sync event from Input Event Device");
break;
// Keyboard event
case EV_KEY:
{
// code == scan code of the key (KEY_xxxx defines in input.h)
// value == 0 key has been released
// value == 1 key has been pressed
// value == 2 repeated key reporting (while holding the key)
if (ev->code == KEY_LEFTSHIFT) {
keyb_lshift = ev->value;
} else if (ev->code == KEY_RIGHTSHIFT) {
keyb_rshift = ev->value;
} else if (ev->code == KEY_LEFTCTRL) {
keyb_lctrl = ev->value;
} else if (ev->code == KEY_RIGHTCTRL) {
keyb_rctrl = ev->value;
} else if (ev->code == KEY_LEFTALT) {
keyb_lalt = ev->value;
} else if (ev->code == KEY_RIGHTALT) {
keyb_ralt = ev->value;
} else {
gnash::key::code c = scancode_to_gnash_key(ev->code,
keyb_lshift || keyb_rshift);
// build modifier
int modifier = gnash::key::GNASH_MOD_NONE;
if (keyb_lshift || keyb_rshift) {
modifier = modifier | gnash::key::GNASH_MOD_SHIFT;
}
if (keyb_lctrl || keyb_rctrl) {
modifier = modifier | gnash::key::GNASH_MOD_CONTROL;
}
if (keyb_lalt || keyb_ralt) {
modifier = modifier | gnash::key::GNASH_MOD_ALT;
}
// send event
if (c != gnash::key::INVALID) {
_gui->notify_key_event(c, modifier, ev->value);
activity = true;
}
} // if normal key
break;
} // case EV_KEY
// Mouse
case EV_REL:
log_unimpl("Relative move event from Input Event Device");
// Touchscreen or joystick
break;
case EV_ABS:
log_unimpl("Absolute move event from Input Event Device");
break;
case EV_MSC:
log_unimpl("Misc event from Input Event Device");
break;
case EV_LED:
log_unimpl("LED event from Input Event Device");
break;
case EV_SND:
log_unimpl("Sound event from Input Event Device");
break;
case EV_REP:
log_unimpl("Key autorepeat event from Input Event Device");
break;
case EV_FF:
log_unimpl("Force Feedback event from Input Event Device");
break;
case EV_FF_STATUS:
log_unimpl("Force Feedback status event from Input Event Device");
break;
case EV_PWR:
log_unimpl("Power event from Input Event Device");
break;
}
return activity;
}
gnash::key::code
EventDevice::scancode_to_gnash_key(int code, bool shift)
{
// NOTE: Scancodes are mostly keyboard oriented (ie. Q, W, E, R, T, ...)
// while Gnash codes are mostly ASCII-oriented (A, B, C, D, ...) so no
// direct conversion is possible.
// TODO: This is a very *incomplete* list and I also dislike this method
// very much because it depends on the keyboard layout (ie. pressing "Z"
// on a german keyboard will print "Y" instead). So we need some
// alternative...
switch (code) {
case KEY_1 : return !shift ? gnash::key::_1 : gnash::key::EXCLAM;
case KEY_2 : return !shift ? gnash::key::_2 : gnash::key::DOUBLE_QUOTE;
case KEY_3 : return !shift ? gnash::key::_3 : gnash::key::HASH;
case KEY_4 : return !shift ? gnash::key::_4 : gnash::key::DOLLAR;
case KEY_5 : return !shift ? gnash::key::_5 : gnash::key::PERCENT;
case KEY_6 : return !shift ? gnash::key::_6 : gnash::key::AMPERSAND;
case KEY_7 : return !shift ? gnash::key::_7 : gnash::key::SINGLE_QUOTE;
case KEY_8 : return !shift ? gnash::key::_8 : gnash::key::PAREN_LEFT;
case KEY_9 : return !shift ? gnash::key::_9 : gnash::key::PAREN_RIGHT;
case KEY_0 : return !shift ? gnash::key::_0 : gnash::key::ASTERISK;
case KEY_A : return shift ? gnash::key::A : gnash::key::a;
case KEY_B : return shift ? gnash::key::B : gnash::key::b;
case KEY_C : return shift ? gnash::key::C : gnash::key::c;
case KEY_D : return shift ? gnash::key::D : gnash::key::d;
case KEY_E : return shift ? gnash::key::E : gnash::key::e;
case KEY_F : return shift ? gnash::key::F : gnash::key::f;
case KEY_G : return shift ? gnash::key::G : gnash::key::g;
case KEY_H : return shift ? gnash::key::H : gnash::key::h;
case KEY_I : return shift ? gnash::key::I : gnash::key::i;
case KEY_J : return shift ? gnash::key::J : gnash::key::j;
case KEY_K : return shift ? gnash::key::K : gnash::key::k;
case KEY_L : return shift ? gnash::key::L : gnash::key::l;
case KEY_M : return shift ? gnash::key::M : gnash::key::m;
case KEY_N : return shift ? gnash::key::N : gnash::key::n;
case KEY_O : return shift ? gnash::key::O : gnash::key::o;
case KEY_P : return shift ? gnash::key::P : gnash::key::p;
case KEY_Q : return shift ? gnash::key::Q : gnash::key::q;
case KEY_R : return shift ? gnash::key::R : gnash::key::r;
case KEY_S : return shift ? gnash::key::S : gnash::key::s;
case KEY_T : return shift ? gnash::key::T : gnash::key::t;
case KEY_U : return shift ? gnash::key::U : gnash::key::u;
case KEY_V : return shift ? gnash::key::V : gnash::key::v;
case KEY_W : return shift ? gnash::key::W : gnash::key::w;
case KEY_X : return shift ? gnash::key::X : gnash::key::x;
case KEY_Y : return shift ? gnash::key::Y : gnash::key::y;
case KEY_Z : return shift ? gnash::key::Z : gnash::key::z;
case KEY_F1 : return gnash::key::F1;
case KEY_F2 : return gnash::key::F2;
case KEY_F3 : return gnash::key::F3;
case KEY_F4 : return gnash::key::F4;
case KEY_F5 : return gnash::key::F5;
case KEY_F6 : return gnash::key::F6;
case KEY_F7 : return gnash::key::F7;
case KEY_F8 : return gnash::key::F8;
case KEY_F9 : return gnash::key::F9;
case KEY_F10 : return gnash::key::F10;
case KEY_F11 : return gnash::key::F11;
case KEY_F12 : return gnash::key::F12;
case KEY_KP0 : return gnash::key::KP_0;
case KEY_KP1 : return gnash::key::KP_1;
case KEY_KP2 : return gnash::key::KP_2;
case KEY_KP3 : return gnash::key::KP_3;
case KEY_KP4 : return gnash::key::KP_4;
case KEY_KP5 : return gnash::key::KP_5;
case KEY_KP6 : return gnash::key::KP_6;
case KEY_KP7 : return gnash::key::KP_7;
case KEY_KP8 : return gnash::key::KP_8;
case KEY_KP9 : return gnash::key::KP_9;
case KEY_KPMINUS : return gnash::key::KP_SUBTRACT;
case KEY_KPPLUS : return gnash::key::KP_ADD;
case KEY_KPDOT : return gnash::key::KP_DECIMAL;
case KEY_KPASTERISK : return gnash::key::KP_MULTIPLY;
case KEY_KPENTER : return gnash::key::KP_ENTER;
case KEY_ESC : return gnash::key::ESCAPE;
case KEY_MINUS : return gnash::key::MINUS;
case KEY_EQUAL : return gnash::key::EQUALS;
case KEY_BACKSPACE : return gnash::key::BACKSPACE;
case KEY_TAB : return gnash::key::TAB;
case KEY_LEFTBRACE : return gnash::key::LEFT_BRACE;
case KEY_RIGHTBRACE : return gnash::key::RIGHT_BRACE;
case KEY_ENTER : return gnash::key::ENTER;
case KEY_LEFTCTRL : return gnash::key::CONTROL;
case KEY_SEMICOLON : return gnash::key::SEMICOLON;
//case KEY_APOSTROPHE : return gnash::key::APOSTROPHE;
//case KEY_GRAVE : return gnash::key::GRAVE;
case KEY_LEFTSHIFT : return gnash::key::SHIFT;
case KEY_BACKSLASH : return gnash::key::BACKSLASH;
case KEY_COMMA : return gnash::key::COMMA;
case KEY_SLASH : return gnash::key::SLASH;
case KEY_RIGHTSHIFT : return gnash::key::SHIFT;
case KEY_LEFTALT : return gnash::key::ALT;
case KEY_SPACE : return gnash::key::SPACE;
case KEY_CAPSLOCK : return gnash::key::CAPSLOCK;
case KEY_NUMLOCK : return gnash::key::NUM_LOCK;
//case KEY_SCROLLLOCK : return gnash::key::SCROLLLOCK;
case KEY_UP : return gnash::key::UP;
case KEY_DOWN : return gnash::key::DOWN;
case KEY_LEFT : return gnash::key::LEFT;
case KEY_RIGHT : return gnash::key::RIGHT;
case KEY_PAGEUP : return gnash::key::PGUP;
case KEY_PAGEDOWN : return gnash::key::PGDN;
case KEY_INSERT : return gnash::key::INSERT;
case KEY_DELETE : return gnash::key::DELETEKEY;
case KEY_HOME : return gnash::key::HOME;
case KEY_END : return gnash::key::END;
}
return gnash::key::INVALID;
}
// This looks in the input event devices
std::vector<boost::shared_ptr<InputDevice> >
EventDevice::scanForDevices(Gui *gui)
{
// GNASH_REPORT_FUNCTION;
struct stat st;
int total = 0;
std::vector<boost::shared_ptr<InputDevice> > devices;
// The default path for input event devices.
char *filespec = strdup("/dev/input/eventX");
int len = strlen(filespec) - 1;
// Walk through all the input event devices for the ones that
// match the type we want. There can be multiple devices of the same
// type, so we return the ID of the event devices.
filespec[len] = '0';
int fd = 0;
while (fd >= 0) {
// First see if the file exists
if (stat(filespec, &st) == 0) {
// Then see if we can open it
if ((fd = open(filespec, O_RDWR)) < 0) {
log_error("You don't have the proper permissions to open %s",
filespec);
// Try the next input event device file
total++;
filespec[len] = '0' + total;
fd = 0;
continue;
}
} else {
// No more device files to try, so we're done scanning
break;
}
char name[256] = "Unknown";
if(ioctl(fd, EVIOCGNAME(sizeof(name)), name) < 0) {
perror("evdev ioctl");
}
log_debug("The device on %s says its name is %s", filespec, name);
struct input_id device_info;
if(ioctl(fd, EVIOCGID, &device_info)) {
perror("evdev ioctl");
}
log_debug("vendor %04hx product %04hx version %04hx",
device_info.vendor, device_info.product,
device_info.version);
close(fd);
boost::shared_ptr<InputDevice> dev;
dev = boost::shared_ptr<InputDevice>(new EventDevice(gui));
// For now we only want keyboards, as the mouse interface
// default of /dev/input/mice supports hotpluging devices,
// unlike the regular event.
if (dev->init(filespec, DEFAULT_BUFFER_SIZE)) {
if ((dev->getType() == InputDevice::KEYBOARD)) {
devices.push_back(dev);
}
}
// dev->dump();
// setup the next device filespec to try
total++;
filespec[len] = '0' + total;
}
free (filespec);
return devices;
}
// end of namespace
}
// local Variables:
// mode: C++
// indent-tabs-mode: nil
// End: