keyhook.c
author Ryan C. Gordon <icculus@icculus.org>
Mon, 23 Dec 2013 23:49:11 -0500
changeset 17 e884dbb403cc
child 45 cf6a06f368e6
permissions -rw-r--r--
Added keyhook code, reworked things to use it.
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
17
e884dbb403cc Added keyhook code, reworked things to use it.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
     1
// !!! FIXME: this is X11 specific.  :(
e884dbb403cc Added keyhook code, reworked things to use it.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
     2
e884dbb403cc Added keyhook code, reworked things to use it.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
     3
#include <stdio.h>
e884dbb403cc Added keyhook code, reworked things to use it.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
     4
#include <stdlib.h>
e884dbb403cc Added keyhook code, reworked things to use it.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
     5
#include <string.h>
e884dbb403cc Added keyhook code, reworked things to use it.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
     6
#include <pthread.h>
e884dbb403cc Added keyhook code, reworked things to use it.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
     7
#include <unistd.h>
e884dbb403cc Added keyhook code, reworked things to use it.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
     8
e884dbb403cc Added keyhook code, reworked things to use it.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
     9
#include <X11/Xlib.h>
e884dbb403cc Added keyhook code, reworked things to use it.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
    10
#include <X11/Xlibint.h>
e884dbb403cc Added keyhook code, reworked things to use it.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
    11
#include <X11/extensions/record.h>
e884dbb403cc Added keyhook code, reworked things to use it.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
    12
e884dbb403cc Added keyhook code, reworked things to use it.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
    13
#include "keyhook.h"
e884dbb403cc Added keyhook code, reworked things to use it.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
    14
e884dbb403cc Added keyhook code, reworked things to use it.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
    15
static volatile int keyPressFlags = 0;
e884dbb403cc Added keyhook code, reworked things to use it.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
    16
static volatile int sawKeyCombo = 0;
e884dbb403cc Added keyhook code, reworked things to use it.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
    17
static void keyhookCallback(XPointer priv, XRecordInterceptData *data)
e884dbb403cc Added keyhook code, reworked things to use it.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
    18
{
e884dbb403cc Added keyhook code, reworked things to use it.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
    19
    const xEvent *xev = (const xEvent *) data->data;
e884dbb403cc Added keyhook code, reworked things to use it.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
    20
    if (data->category == XRecordFromServer)
e884dbb403cc Added keyhook code, reworked things to use it.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
    21
    {
e884dbb403cc Added keyhook code, reworked things to use it.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
    22
        const BYTE keycode = xev->u.u.detail;
e884dbb403cc Added keyhook code, reworked things to use it.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
    23
        if (xev->u.u.type == KeyPress)
e884dbb403cc Added keyhook code, reworked things to use it.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
    24
        {
e884dbb403cc Added keyhook code, reworked things to use it.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
    25
            // !!! FIXME: don't hardcode these keycodes.
e884dbb403cc Added keyhook code, reworked things to use it.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
    26
            if ((keycode == 64) && (keyPressFlags == 0))
e884dbb403cc Added keyhook code, reworked things to use it.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
    27
                keyPressFlags++;
e884dbb403cc Added keyhook code, reworked things to use it.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
    28
            else if ((keycode == 133) && (keyPressFlags == 1))
e884dbb403cc Added keyhook code, reworked things to use it.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
    29
                keyPressFlags++;
e884dbb403cc Added keyhook code, reworked things to use it.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
    30
            else if ((keycode == 51) && (keyPressFlags == 2))
e884dbb403cc Added keyhook code, reworked things to use it.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
    31
            {
e884dbb403cc Added keyhook code, reworked things to use it.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
    32
                sawKeyCombo = 1;
e884dbb403cc Added keyhook code, reworked things to use it.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
    33
                keyPressFlags = 0;
e884dbb403cc Added keyhook code, reworked things to use it.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
    34
            } // else if
e884dbb403cc Added keyhook code, reworked things to use it.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
    35
            else
e884dbb403cc Added keyhook code, reworked things to use it.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
    36
                keyPressFlags = 0;
e884dbb403cc Added keyhook code, reworked things to use it.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
    37
        } // if
e884dbb403cc Added keyhook code, reworked things to use it.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
    38
        else if (xev->u.u.type == KeyRelease)
e884dbb403cc Added keyhook code, reworked things to use it.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
    39
        {
e884dbb403cc Added keyhook code, reworked things to use it.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
    40
            keyPressFlags = 0;
e884dbb403cc Added keyhook code, reworked things to use it.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
    41
        } // else if
e884dbb403cc Added keyhook code, reworked things to use it.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
    42
    } // if
e884dbb403cc Added keyhook code, reworked things to use it.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
    43
e884dbb403cc Added keyhook code, reworked things to use it.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
    44
    XRecordFreeData(data);
e884dbb403cc Added keyhook code, reworked things to use it.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
    45
} // keyhookCallback
e884dbb403cc Added keyhook code, reworked things to use it.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
    46
e884dbb403cc Added keyhook code, reworked things to use it.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
    47
e884dbb403cc Added keyhook code, reworked things to use it.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
    48
// every example I've seen needs two Display connections...one for the
e884dbb403cc Added keyhook code, reworked things to use it.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
    49
//  keyhook, and one to control it.
e884dbb403cc Added keyhook code, reworked things to use it.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
    50
static Display *ctrldpy = NULL;
e884dbb403cc Added keyhook code, reworked things to use it.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
    51
static Display *datadpy = NULL;
e884dbb403cc Added keyhook code, reworked things to use it.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
    52
static XRecordContext xrc = 0;
e884dbb403cc Added keyhook code, reworked things to use it.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
    53
e884dbb403cc Added keyhook code, reworked things to use it.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
    54
int initKeyHook(void)
e884dbb403cc Added keyhook code, reworked things to use it.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
    55
{
e884dbb403cc Added keyhook code, reworked things to use it.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
    56
    int major = 0;
e884dbb403cc Added keyhook code, reworked things to use it.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
    57
    int minor = 0;
e884dbb403cc Added keyhook code, reworked things to use it.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
    58
    XRecordRange *xrr = NULL;
e884dbb403cc Added keyhook code, reworked things to use it.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
    59
    XRecordClientSpec xrcs = XRecordAllClients;
e884dbb403cc Added keyhook code, reworked things to use it.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
    60
e884dbb403cc Added keyhook code, reworked things to use it.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
    61
    if (ctrldpy)
e884dbb403cc Added keyhook code, reworked things to use it.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
    62
        return 0;  // already initialized.
e884dbb403cc Added keyhook code, reworked things to use it.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
    63
e884dbb403cc Added keyhook code, reworked things to use it.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
    64
    ctrldpy = XOpenDisplay(NULL);
e884dbb403cc Added keyhook code, reworked things to use it.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
    65
    if (!ctrldpy)
e884dbb403cc Added keyhook code, reworked things to use it.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
    66
        goto failed;
e884dbb403cc Added keyhook code, reworked things to use it.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
    67
e884dbb403cc Added keyhook code, reworked things to use it.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
    68
    XSynchronize(ctrldpy, True);
e884dbb403cc Added keyhook code, reworked things to use it.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
    69
e884dbb403cc Added keyhook code, reworked things to use it.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
    70
    datadpy = XOpenDisplay(NULL);
e884dbb403cc Added keyhook code, reworked things to use it.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
    71
    if (!datadpy)
e884dbb403cc Added keyhook code, reworked things to use it.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
    72
        goto failed;
e884dbb403cc Added keyhook code, reworked things to use it.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
    73
    else if (!XRecordQueryVersion(ctrldpy, &major, &minor))
e884dbb403cc Added keyhook code, reworked things to use it.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
    74
        goto failed;
e884dbb403cc Added keyhook code, reworked things to use it.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
    75
    else if ((xrr = XRecordAllocRange()) == NULL)
e884dbb403cc Added keyhook code, reworked things to use it.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
    76
        goto failed;
e884dbb403cc Added keyhook code, reworked things to use it.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
    77
e884dbb403cc Added keyhook code, reworked things to use it.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
    78
    memset(xrr, '\0', sizeof (*xrr));
e884dbb403cc Added keyhook code, reworked things to use it.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
    79
    xrr->device_events.first = KeyPress;
e884dbb403cc Added keyhook code, reworked things to use it.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
    80
    xrr->device_events.last = KeyPress;
e884dbb403cc Added keyhook code, reworked things to use it.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
    81
e884dbb403cc Added keyhook code, reworked things to use it.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
    82
    if ((xrc = XRecordCreateContext(ctrldpy, 0, &xrcs, 1, &xrr, 1)) == 0)
e884dbb403cc Added keyhook code, reworked things to use it.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
    83
        goto failed;
e884dbb403cc Added keyhook code, reworked things to use it.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
    84
    else if (!XRecordEnableContextAsync(datadpy, xrc, keyhookCallback, NULL))
e884dbb403cc Added keyhook code, reworked things to use it.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
    85
        goto failed;
e884dbb403cc Added keyhook code, reworked things to use it.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
    86
e884dbb403cc Added keyhook code, reworked things to use it.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
    87
    XFree(xrr);
e884dbb403cc Added keyhook code, reworked things to use it.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
    88
    xrr = NULL;
e884dbb403cc Added keyhook code, reworked things to use it.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
    89
e884dbb403cc Added keyhook code, reworked things to use it.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
    90
    return 1;
e884dbb403cc Added keyhook code, reworked things to use it.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
    91
e884dbb403cc Added keyhook code, reworked things to use it.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
    92
failed:
e884dbb403cc Added keyhook code, reworked things to use it.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
    93
    deinitKeyHook();
e884dbb403cc Added keyhook code, reworked things to use it.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
    94
    if (xrr) XFree(xrr);
e884dbb403cc Added keyhook code, reworked things to use it.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
    95
e884dbb403cc Added keyhook code, reworked things to use it.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
    96
    return 0;
e884dbb403cc Added keyhook code, reworked things to use it.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
    97
} // initKeyHook
e884dbb403cc Added keyhook code, reworked things to use it.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
    98
e884dbb403cc Added keyhook code, reworked things to use it.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
    99
e884dbb403cc Added keyhook code, reworked things to use it.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   100
void deinitKeyHook(void)
e884dbb403cc Added keyhook code, reworked things to use it.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   101
{
e884dbb403cc Added keyhook code, reworked things to use it.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   102
    if (ctrldpy)
e884dbb403cc Added keyhook code, reworked things to use it.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   103
    {
e884dbb403cc Added keyhook code, reworked things to use it.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   104
        if (xrc)
e884dbb403cc Added keyhook code, reworked things to use it.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   105
        {
e884dbb403cc Added keyhook code, reworked things to use it.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   106
            XRecordDisableContext(ctrldpy, xrc);
e884dbb403cc Added keyhook code, reworked things to use it.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   107
            XRecordFreeContext(ctrldpy, xrc);
e884dbb403cc Added keyhook code, reworked things to use it.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   108
        } // if
e884dbb403cc Added keyhook code, reworked things to use it.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   109
        XCloseDisplay(ctrldpy);
e884dbb403cc Added keyhook code, reworked things to use it.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   110
    } // if
e884dbb403cc Added keyhook code, reworked things to use it.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   111
e884dbb403cc Added keyhook code, reworked things to use it.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   112
    if (datadpy)
e884dbb403cc Added keyhook code, reworked things to use it.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   113
        XCloseDisplay(datadpy);
e884dbb403cc Added keyhook code, reworked things to use it.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   114
e884dbb403cc Added keyhook code, reworked things to use it.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   115
    ctrldpy = NULL;
e884dbb403cc Added keyhook code, reworked things to use it.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   116
    datadpy = NULL;
e884dbb403cc Added keyhook code, reworked things to use it.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   117
    xrc = 0;
e884dbb403cc Added keyhook code, reworked things to use it.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   118
    sawKeyCombo = 0;
e884dbb403cc Added keyhook code, reworked things to use it.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   119
    keyPressFlags = 0;
e884dbb403cc Added keyhook code, reworked things to use it.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   120
} // deinitKeyHook
e884dbb403cc Added keyhook code, reworked things to use it.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   121
e884dbb403cc Added keyhook code, reworked things to use it.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   122
e884dbb403cc Added keyhook code, reworked things to use it.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   123
int pumpKeyHook(void)
e884dbb403cc Added keyhook code, reworked things to use it.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   124
{
e884dbb403cc Added keyhook code, reworked things to use it.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   125
    if (!datadpy)
e884dbb403cc Added keyhook code, reworked things to use it.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   126
        return 0;
e884dbb403cc Added keyhook code, reworked things to use it.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   127
e884dbb403cc Added keyhook code, reworked things to use it.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   128
    sawKeyCombo = 0;
e884dbb403cc Added keyhook code, reworked things to use it.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   129
    XRecordProcessReplies(datadpy);
e884dbb403cc Added keyhook code, reworked things to use it.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   130
    return sawKeyCombo;
e884dbb403cc Added keyhook code, reworked things to use it.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   131
} // pumpKeyHook
e884dbb403cc Added keyhook code, reworked things to use it.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   132
e884dbb403cc Added keyhook code, reworked things to use it.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   133
// end of keyhook.c ...
e884dbb403cc Added keyhook code, reworked things to use it.
Ryan C. Gordon <icculus@icculus.org>
parents:
diff changeset
   134