• Stars
    star
    264
  • Rank 155,103 (Top 4 %)
  • Language
    C++
  • License
    MIT License
  • Created almost 10 years ago
  • Updated almost 7 years ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

OSX IOKit driver for implementing virtual HID devices (joypads, keyboards, mices, ...) from userspace

foohid

OSX IOKit driver for implementing virtual HID devices from userspace.

*** The foohid driver is currently unsupported and lacks proper thread-safety (leading to security problems), please do not use it in production unless you want to sponsor the project contacting info at unbit dot it ***

Examples

You can check the examples section below, the examples directory or use the Python 2 wrapper (next section).

The Python 2 wrapper

You can use the official Python 2 wrapper (available on PyPi and here) to start playing with virtual HID devices. First of all, install the foohid Python 2 extension:

pip install foohid

Now clone the foohid-py repository:

git clone https://github.com/unbit/foohid-py
cd foohid-py

Three tests are available inside the repository directory:

  • test_mouse.py will create a virtual mouse. Just run it and every second your mouse pointer will move to a random position of the screen.
  • test_joypad.py will create a virtual joypad. Just run it and every second left and right axes will be updated.
  • test_list.py will show the listing feature (a bunch of virtual devices will be created, then listed and destroyed).

Note: Python 3 support should be ready soon.

A C example (with report descriptor)

Building report descriptors is a really annoying task. To simplify testing, the following describes a generic mouse (thanks eleccelerator).

unsigned char report_descriptor[] = {
    0x05, 0x01,                    // USAGE_PAGE (Generic Desktop)
    0x09, 0x02,                    // USAGE (Mouse)
    0xa1, 0x01,                    // COLLECTION (Application)
    0x09, 0x01,                    //   USAGE (Pointer)
    0xa1, 0x00,                    //   COLLECTION (Physical)
    0x05, 0x09,                    //     USAGE_PAGE (Button)
    0x19, 0x01,                    //     USAGE_MINIMUM (Button 1)
    0x29, 0x03,                    //     USAGE_MAXIMUM (Button 3)
    0x15, 0x00,                    //     LOGICAL_MINIMUM (0)
    0x25, 0x01,                    //     LOGICAL_MAXIMUM (1)
    0x95, 0x03,                    //     REPORT_COUNT (3)
    0x75, 0x01,                    //     REPORT_SIZE (1)
    0x81, 0x02,                    //     INPUT (Data,Var,Abs)
    0x95, 0x01,                    //     REPORT_COUNT (1)
    0x75, 0x05,                    //     REPORT_SIZE (5)
    0x81, 0x03,                    //     INPUT (Cnst,Var,Abs)
    0x05, 0x01,                    //     USAGE_PAGE (Generic Desktop)
    0x09, 0x30,                    //     USAGE (X)
    0x09, 0x31,                    //     USAGE (Y)
    0x15, 0x81,                    //     LOGICAL_MINIMUM (-127)
    0x25, 0x7f,                    //     LOGICAL_MAXIMUM (127)
    0x75, 0x08,                    //     REPORT_SIZE (8)
    0x95, 0x02,                    //     REPORT_COUNT (2)
    0x81, 0x06,                    //     INPUT (Data,Var,Rel)
    0xc0,                          //   END_COLLECTION
    0xc0                           // END_COLLECTION
}

It maps to the following structure:

struct mouse_report_t {
    uint8_t buttons;
    int8_t x;
    int8_t y;
}

To create and move around a virtual mouse:

#include <IOKit/IOKitLib.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

unsigned char report_descriptor[] = {
    // ...
};

struct mouse_report_t {
    // ...
};

#define SERVICE_NAME "it_unbit_foohid"

#define FOOHID_CREATE 0  // create selector
#define FOOHID_SEND 2  // send selector

#define DEVICE_NAME "Foohid Virtual Mouse"
#define DEVICE_SN "SN 123456"

int main() {
    io_iterator_t iterator;
    io_service_t service;
    io_connect_t connect;

    // Get a reference to the IOService
    kern_return_t ret = IOServiceGetMatchingServices(kIOMasterPortDefault, IOServiceMatching(SERVICE_NAME), &iterator);

    if (ret != KERN_SUCCESS) {
        printf("Unable to access IOService.\n");
        exit(1);
    }

    // Iterate till success
    int found = 0;
    while ((service = IOIteratorNext(iterator)) != IO_OBJECT_NULL) {
        ret = IOServiceOpen(service, mach_task_self(), 0, &connect);

        if (ret == KERN_SUCCESS) {
            found = 1;
            break;
        }

        IOObjectRelease(service);
    }
    IOObjectRelease(iterator);

    if (!found) {
        printf("Unable to open IOService.\n");
        exit(1);
    }

    // Fill up the input arguments.
    uint32_t input_count = 8;
    uint64_t input[input_count];
    input[0] = (uint64_t) strdup(DEVICE_NAME);  // device name
    input[1] = strlen((char *)input[0]);  // name length
    input[2] = (uint64_t) report_descriptor;  // report descriptor
    input[3] = sizeof(report_descriptor);  // report descriptor len
    input[4] = (uint64_t) strdup(DEVICE_SN);  // serial number
    input[5] = strlen((char *)input[4]);  // serial number len
    input[6] = (uint64_t) 2;  // vendor ID
    input[7] = (uint64_t) 3;  // device ID

    ret = IOConnectCallScalarMethod(connect, FOOHID_CREATE, input, input_count, NULL, 0);
    if (ret != KERN_SUCCESS) {
        printf("Unable to create HID device. May be fine if created previously.\n");
    }

    // Arguments to be passed through the HID message.
    struct mouse_report_t mouse;
    uint32_t send_count = 4;
    uint64_t send[send_count];
    send[0] = (uint64_t)input[0];  // device name
    send[1] = strlen((char *)input[0]);  // name length
    send[2] = (uint64_t) &mouse;  // mouse struct
    send[3] = sizeof(struct mouse_report_t);  // mouse struct len

    for(;;) {
        mouse.buttons = 0;
        mouse.x = rand();
        mouse.y = rand();

        ret = IOConnectCallScalarMethod(connect, FOOHID_SEND, send, send_count, NULL, 0);
        if (ret != KERN_SUCCESS) {
            printf("Unable to send message to HID device.\n");
        }

        sleep(1);  // sleep for a second
    }
}

Run it

You can found the previous example here. Compile it and run it with:

curl -O https://raw.githubusercontent.com/unbit/foohid/develop/examples/mouse.c
gcc mouse.c -o virtual_mouse -framework IOKit
./virtual_mouse

Other examples

A few other examples may be found within the examples directory. One that is worth noticing is the keyboard example.

The IOUserClient API specification

4 methods are exposed:

  • CREATE (selector 0)
  • DESTROY (selector 1)
  • SEND (selector 2)
  • LIST (selector 3)

Create

Creates a new fake/virtual HID device with the specified report_descriptor.

Takes 8 input arguments:

  1. name pointer.
  2. name length.
  3. report_descriptor pointer.
  4. report_descriptor length.
  5. device serial number pointer.
  6. device serial number pointer length.
  7. device vendor ID.
  8. device product ID.

And doesn't output any argument.

Destroy

Takes 2 input arguments:

  1. name pointer.
  2. name length.

And doesn't output any argument.

Send

Generate a HID event from a previously created fake/virtual HID device.

Takes 4 input arguments:

  1. name pointer.
  2. name length.
  3. report_descriptor pointer.
  4. report_descriptor length.

And doesn't output any argument.

List

Return (into the supplied buffer pointer) the list of available fake/virtual devices separated by \0. The items output value contains the number of returned items. If the supplied buffer is not big enough, the needed bytes value contains a suggestion for a second run.

Takes 2 input arguments:

  1. buffer pointer.
  2. buffer length.

And 2 output arguments:

  1. needed bytes (suggestion for next run)
  2. returned items.

Logging

Logging is disabled by default. You can enable it by building a DEBUG version by using XCode, or manually setting the -DDEBUG preprocessor flag.

More Repositories

1

uwsgi

uWSGI application server container
C
3,459
star
2

uwsgi-docs

Official uWSGI docs, examples, tutorials, tips and tricks
Python
640
star
3

vpn-ws

A VPN system over websockets
C
606
star
4

spockfs

SpockFS is an HTTP based network filesystem
C
307
star
5

django-uwsgi

Django related examples/trick/modules for uWSGI
Python
211
star
6

blastbeat

The BlastBeat server
C
159
star
7

uwsgi.it

The next-generation Unbit hosting platform
Python
77
star
8

uwsgi-docker

uWSGI plugin for integration with Docker
C
66
star
9

sftpclone

A tool for cloning/syncing a local directory tree with an SFTP server
Python
52
star
10

uwsgi-sentry

uWSGI plugin for sentry integration
C
49
star
11

uwsgi-realtime

a uWSGI plugin exposing offloaded realtime features like SSE, socket.io and media streaming
C
38
star
12

pysftpserver

An OpenSSH sftp wrapper in python
Python
36
star
13

uwsgi-consul

uWSGI plugin for consul integration
C
29
star
14

davvy

A Django application for building WebDAV services
Python
25
star
15

uwsgi-sse-offload

uWSGI offload bridge between redis pubsub and server sent events (sse)
C
23
star
16

librethinkdb

a c library for accessing rethinkdb servers
C
23
star
17

uwsgi-phpsgi

uWSGI experimental plugin for implementing a WSGI/PSGI/Rack-like interface for php
C
20
star
18

gitwhoosh

A git repository indexer (using whoosh as the engine)
Python
19
star
19

foohid-py

Python wrapper for the foohid OSX driver
C
18
star
20

spoolgore

A simple mail "spool and send" daemon written in Go
Go
14
star
21

uwsgi-rust

uWSGI and Rust integration plugin
Rust
13
star
22

uwsgi-pgnotify

Maps PostgreSQL notification system to uWSGI signal framework
C
11
star
23

unbit-bars

A Perl Curses::UI interface for uWSGI metrics subsystem
Perl
11
star
24

uwsgi-swift

uWSGI plugin for Apple Swift integration
Objective-C
10
star
25

uwsgi-bonjour

uWSGI plugin for OSX bonjour services integration
C
9
star
26

pydrone

run sandboxed javascript code in your python apps
C
8
star
27

uwsgi-capture

uWSGI plugin for accessing video capture devices
C
8
star
28

uwsgi-eventfd

uWSGI plugin for Linux eventfd() syscall integration
C
7
star
29

uwsgi-influxdb

uWSGI plugin for influxdb integration
C
7
star
30

uwsgi-wstcp

uWSGI plugin mapping websockets to tcp sockets
C
7
star
31

ulver

Unbit Lisp Version
C
7
star
32

uwsgi-node-rpc-server

A simple uwsgi-RPC server written in node.js
JavaScript
7
star
33

dockstrap

Like debootstrap but uses docker registry
Python
6
star
34

uwsgi-datadog

uWSGI plugin for datadog integration
C
6
star
35

uwebsocketconnection

an attempt to run websockets over uwsgi http router using gevent or uGreen
6
star
36

uwsgi-alarm-socket

uWSGI simple plugin for monitoring sockets
C
6
star
37

uwsgi-hetzner

A uWSGI legion action for managing hetzner's failover ip service
6
star
38

uwsgi-pushover

uWSGI plugin for sending pushover notifications (https://pushover.net/)
C
5
star
39

9spock

A high performance, featureful 9p fileserver for containers
5
star
40

uwsgi-apparmor

uWSGI integration with apparmor
C
4
star
41

uwsgi-riemann

uWSGI plugin for riemann integration
C
4
star
42

uwsgi-netlink

uWSGI plugin exposing netlink features
C
4
star
43

uwsgi-ganglia

uWSGI plugin for Ganglia integration
C
4
star
44

uwsgi-cares

uWSGI plugin for integration with the c-ares async dns library
C
3
star
45

uwsgi-gif

uWSGI plugin for dynamic generation of simple gif images
C
3
star
46

uwsgi-qtloop

Qt loop engine for uWSGI
C++
2
star
47

uwsgi-strophe

uWSGI plugin for libstrophe integration (xmpp)
C
2
star
48

uwsgi-java-servlet

experimental uWSGI plugin implementing java servlet 2.5
Java
2
star
49

unbit-docs

Documentazione per deployment su piattaforma Unbit
HTML
2
star
50

unbit.github.com

JavaScript
2
star
51

perl-net-uwsgi

perl module for easy interaction with uWSGI servers
Perl
2
star
52

uwsgi-alarm-chain

uWSGI plugin for mapping multiple alarms to a single event
C
2
star
53

aivengine

AIV Simple Game Engine for first year students
C#
2
star
54

pam-unbit

pam module for attaching to namespaced Emperors via setns()
C
1
star
55

moarvm-uwsgi-skel

A skel/base for building a uWSGI moarvm plugin aimed at NQP
C
1
star
56

uwsgi-opentsdb

uWSGI plugin for OpenTSDB integration
C
1
star
57

nss-unbit

nss module for the uwsgi.it service
C
1
star
58

uwsgi-quota

uWSGI plugin for UNIX quota integration
C
1
star
59

uwsgi-console-broadcast

uWSGI plugin exposing hooks for sending broadcast messages to terminals
C
1
star
60

blastbeat-gem

A Ruby module exporting a bunch of utility for integration with the BlastBeat server
Ruby
1
star
61

uwsgi-etcd

uWSGI plugin for etcd integration
1
star
62

uwsgicc

uWSGI Flask example app using the uwsgi api
Python
1
star