Skip to content

Commit

Permalink
Make some of the input drivers a bit more robust.
Browse files Browse the repository at this point in the history
  • Loading branch information
Alcaro committed Jan 1, 2015
1 parent c48e30f commit 3b40e43
Show file tree
Hide file tree
Showing 7 changed files with 67 additions and 49 deletions.
13 changes: 8 additions & 5 deletions inputkb-gdk.cpp
Expand Up @@ -12,7 +12,6 @@ namespace {

class inputkb_gdk : public inputkb {
public:
GdkDisplay* display;
GdkDeviceManager* devicemanager;
GtkWidget* widget;//likely a GtkWindow, but we only use it as GtkWidget so let's keep it as that.

Expand Down Expand Up @@ -86,6 +85,10 @@ void device_remove(GdkDeviceManager* object, GdkDevice* device)
{
for (unsigned int i=0;i<this->numdevices;i++)
{
for (unsigned int j=0;j<256;j++)
{
this->key_cb(i, j, inputkb::translate_scan(j), false);
}
if (this->devices[i]==device) this->devices[i]=NULL;
}
}
Expand All @@ -100,9 +103,9 @@ gboolean key_action(GtkWidget* widget, GdkEvent* event)
{
GdkDevice* device=gdk_event_get_source_device(event);

if (gdk_device_get_device_type(device)==GDK_DEVICE_TYPE_MASTER) return FALSE;
//for some reason, repeated keystrokes come from the master device, which screws up device ID assignments
//we don't want repeats all, let's just kill them.
if (gdk_device_get_device_type(device)==GDK_DEVICE_TYPE_MASTER) return FALSE;

unsigned int kb=find_or_allocate_id_for(device);

Expand Down Expand Up @@ -130,15 +133,15 @@ static gboolean key_action_s(GtkWidget* widget, GdkEvent* event, gpointer user_d
inputkb_gdk(uintptr_t windowhandle)
{
#ifdef WNDPROT_X11
this->display=gdk_x11_lookup_xdisplay(window_x11.display);
GdkDisplay* display=gdk_x11_lookup_xdisplay(window_x11.display);
#else
#error Fill this in.
#endif
this->devicemanager=gdk_display_get_device_manager(this->display);
this->devicemanager=gdk_display_get_device_manager(display);
//g_signal_connect(this->devicemanager, "device-added", G_CALLBACK(device_add_s), this);
g_signal_connect(this->devicemanager, "device-removed", G_CALLBACK(device_remove_s), this);

gdk_window_get_user_data(gdk_x11_window_lookup_for_display(this->display, windowhandle), (void**)&this->widget);
gdk_window_get_user_data(gdk_x11_window_lookup_for_display(display, windowhandle), (void**)&this->widget);
//we probably have a GtkDrawingArea, and those can't have keyboard focus. Let's ask for the GtkWindow it is in instead.
this->widget=gtk_widget_get_toplevel(this->widget);
gtk_widget_add_events(this->widget, GDK_KEY_PRESS_MASK|GDK_KEY_RELEASE_MASK);
Expand Down
21 changes: 14 additions & 7 deletions inputkb-udev.cpp
Expand Up @@ -165,16 +165,23 @@ void inputkb_udev::fd_activity(int fd)
//https://www.kernel.org/doc/Documentation/input/input.txt says
//"and you'll always get a whole number of input events on a read"
//their size is constant, no need to do anything weird
while (read(fd, &ev, sizeof(ev)) > 0)
another:
ssize_t nbyte = read(fd, &ev, sizeof(ev));
if (nbyte<=0)
{
if (ev.type==EV_KEY)
for (unsigned int i=0;i<256;i++)//release all keys if the keyboad is unplugged
{
int scan=linuxcode_to_scan(fd, ev.code);
if (scan<0) continue;
//printf("evc=%.2X sc=%.2X\n",ev.code,scan);
this->key_cb(this->fd[id].id,
scan, inputkb::translate_scan(scan), (ev.value!=0));//ev.value==2 means repeated
this->key_cb(this->fd[id].id, i, inputkb::translate_scan(i), false);
}
fd_unwatch(id);
}
if (ev.type==EV_KEY)
{
int scan=linuxcode_to_scan(fd, ev.code);
if (scan<0) goto another;
//printf("evc=%.2X sc=%.2X\n",ev.code,scan);
this->key_cb(this->fd[id].id, scan, inputkb::translate_scan(scan), (ev.value!=0));//ev.value==2 means repeated
goto another;
}
}
}
Expand Down
30 changes: 15 additions & 15 deletions inputkb-x11.cpp
Expand Up @@ -8,23 +8,23 @@
namespace {
class inputkb_x11 : public inputkb {
public:
static const uint32_t features = f_public|f_pollable|f_remote;

void refresh() { poll(); }
void poll()
static const uint32_t features = f_public|f_pollable|f_remote;

void refresh() { poll(); }
void poll()
{
uint8_t state[32];
//this one always succeeds, so this check is pointless, but it feels better that way
//http://cgit.freedesktop.org/xorg/lib/libX11/tree/src/QuKeybd.c
if (!XQueryKeymap(window_x11.display, (char*)state)) return;
for (unsigned int i=0;i<256;i++)
{
uint8_t state[32];
//this one always succeeds, so this check is pointless, but it feels better that way
//http://cgit.freedesktop.org/xorg/lib/libX11/tree/src/QuKeybd.c
if (!XQueryKeymap(window_x11.display, (char*)state)) return;
for (unsigned int i=0;i<256;i++)
{
this->key_cb(0, i, translate_scan(i), state[i>>3]&(1<<(i&7)));
}
this->key_cb(0, i, translate_scan(i), state[i>>3]&(1<<(i&7)));
}

static inputkb* create(uintptr_t windowhandle) { return new inputkb_x11(); }
~inputkb_x11() {}
}

static inputkb* create(uintptr_t windowhandle) { return new inputkb_x11(); }
~inputkb_x11() {}
};

}
Expand Down
9 changes: 4 additions & 5 deletions inputkb.cpp
Expand Up @@ -5,11 +5,10 @@
#undef this

namespace {
class inputkb_none : public inputkb {
~inputkb_none(){}
uint32_t features() { return 0; }
};
inputkb* inputkb_create_none(uintptr_t windowhandle) { return new inputkb_none(); }
class inputkb_none : public inputkb {
~inputkb_none(){}
};
inputkb* inputkb_create_none(uintptr_t windowhandle) { return new inputkb_none(); }
};

const inputkb::driver inputkb::driver_none={ "None", inputkb_create_none, 0 };
Expand Down
39 changes: 24 additions & 15 deletions io.h
Expand Up @@ -43,7 +43,7 @@ class video : nocopy {
// set it up, as a function pointer cannot point to a C++ member.
//On failure, the descriptor is guaranteed to remain sufficiently untouched that creation can be retried
// with another driver, and the results will be the same as if this other driver was the first tried.
//If ::features & f_3d is 0, this can be NULL.
//Can be NULL if features&f_3d == 0.
video* (*create3d)(uintptr_t windowhandle, struct retro_hw_render_callback * desc);

uint32_t features;
Expand Down Expand Up @@ -428,8 +428,9 @@ class inputkb : nocopy {
public:
//It is safe to set this callback multiple times; the latest one applies. It is also safe to not set it at all, though that makes the structure quite useless.
//scancode is in the range -1..1023, and libretrocode is in the range 0..RETROK_LAST-1. keyboard is in 0..31.
//A libretrocode is the same across multiple different drivers (see libretro.h RETROK_ for values); scancodes are not.
//If scancode is -1 or libretrocode is 0, it means that the key does not have any assigned value. (Undefined scancodes are extremely rare, though.)
//It may repeat the current state. It may trigger for scancodes that are impossible to hit.
//It may repeat the current state. It may say 'not pressed' for keys that are impossible to hit on the current hardware.
void set_kb_cb(function<void(unsigned int keyboard, int scancode, unsigned int libretrocode, bool down)> key_cb) { this->key_cb = key_cb; }

//Returns the features this driver supports. Numerically higher is better. Some flags contradict each other.
Expand All @@ -441,7 +442,7 @@ class inputkb : nocopy {
f_background=0x0008,//Can view input events while the window is not focused. Implies f_auto.
f_pollable = 0x0004,//refresh() is implemented.
f_remote = 0x0002,//Compatible with X11 remoting, or equivalent. Implies !f_direct.
f_public = 0x0001,//Does not require elevated privileges to use.
f_public = 0x0001,//Does not require elevated privileges to use. While this is quite important, insufficient privileges make it fail creation, and so it should have little if any effect on creation order.
};
//virtual uint32_t features() = 0; // Features are constantly known at the start.

Expand Down Expand Up @@ -488,23 +489,31 @@ class inputmouse {
static const driver* const drivers[];

protected:
function<void(unsigned int keyboard, int scancode, unsigned int libretrocode, bool down)> key_cb;
//TODO: delta, relative to window top left, or relative to primary monitor? (All three must be signed because Windows is crazy.)
function<void(unsigned int mouse, signed int x, signed int y)> move_cb;

//The "button-press-event" signal
//The "button-release-event" signal
//The "motion-notify-event" signal
//gboolean user_function(GtkWidget* widget, GdkEvent* event, gpointer user_data)
//https://developer.gnome.org/gdk3/stable/gdk3-Events.html#GDK-BUTTON-PRESS-MASK:CAPS
//https://developer.gnome.org/gdk3/stable/gdk3-Events.html#GDK-POINTER-MOTION-MASK:CAPS
//https://developer.gnome.org/gdk3/stable/gdk3-Events.html#GDK-BUTTON-RELEASE-MASK:CAPS
//https://developer.gnome.org/gdk3/stable/gdk3-Event-Structures.html#GdkEventButton
//https://developer.gnome.org/gdk3/stable/gdk3-Event-Structures.html#GdkEventMotion

public:
//It is safe to set this callback multiple times; the latest one applies. It is also safe to not set it at all, though that makes the structure quite useless.
//scancode is in the range -1..1023, and libretrocode is in the range 0..RETROK_LAST-1. keyboard is in 0..31.
//If scancode is -1 or libretrocode is 0, it means that the key does not have any assigned value. (Undefined scancodes are extremely rare, though.)
//It may repeat the current state. It may trigger for scancodes that are impossible to hit.
void set_kb_cb(function<void(unsigned int keyboard, int scancode, unsigned int libretrocode, bool down)> key_cb) { this->key_cb = key_cb; }
//
void set_kb_cb(function<void(unsigned int mouse, signed int x, signed int y)> move_cb) { this->move_cb = move_cb; }

//Returns the features this driver supports. Numerically higher is better. Some flags contradict each other.
enum {
f_multi = 0x0080,//Can differ between multiple mice.
f_delta = 0x0040,//Does not call the callback for unchanged state. Improves processing time.
f_auto = 0x0020,//poll() is empty, and the callback is called by window_run_*(). Implies f_delta.
f_direct = 0x0010,//Does not go through a separate process. Improves latency.
f_background=0x0008,//Can view input events while the window is not focused. Implies f_auto.
f_pollable = 0x0004,//refresh() is implemented.
f_outside = 0x0040,//Reports the mouse position when it's outside the window.
f_bind = 0x0000,//Can 'bind' the mouse, g.
f_multi = 0x0020,//Can differ between multiple mice.
f_auto = 0x0010,//poll() is empty, and the callback is called by window_run_*(). Implies f_delta.
f_direct = 0x0008,//Does not go through a separate process. Improves latency.
f_background=0x0004,//Can view input events while the window is not focused. Implies f_auto.
f_remote = 0x0002,//Compatible with X11 remoting, or equivalent. Implies !f_direct.
f_public = 0x0001,//Does not require elevated privileges to use.
};
Expand Down
2 changes: 1 addition & 1 deletion todo.txt
Expand Up @@ -11,7 +11,7 @@ major:
- add imports
- add parameters
* rewrite input
* C++
- C++
* more input options
* mouse support
* automatic mouse control for scrolling shooters
Expand Down
2 changes: 1 addition & 1 deletion video-shader-translate-cgc.cpp
Expand Up @@ -112,7 +112,7 @@ static const char * const cg_names[]={ CG_SYMS() };
#undef CG_SYM

class cg_translator;
static ptrmap<CGcontext, cg_translator*> cgc_translators;
static ptrmap<CGcontext, cg_translator*> cgc_translators;//TODO: this object is not thread safe.
class cg_translator {
public:

Expand Down

0 comments on commit 3b40e43

Please sign in to comment.