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