unbit / foohid Goto Github PK
View Code? Open in Web Editor NEWOSX IOKit driver for implementing virtual HID devices (joypads, keyboards, mices, ...) from userspace
License: MIT License
OSX IOKit driver for implementing virtual HID devices (joypads, keyboards, mices, ...) from userspace
License: MIT License
I would like to build a virtual webcam. That may be beyond the scope of this project but just trying to get a foot in the door somewhere. Can you point me in a direction? I've written stuff for Android and IOT devices so I'm comfortable with programming in C but I'm new to Mac and your project is the closest thing I've seen to hardware level virtualization.
Hi,
Great project (hope the kext gets signed some day)! Only one minor complaint:
If the C examples are killed with ctrl-c and are run again they don't work because the destroy method
never got called. That confused me at first until I decided to just comment out the corresponding exit(1).
Hi! Firstly, thanks so much for creating this project. I've been working off of the keyboard.c example and encountered a behavior I can't seem to explain and was wondering if it's a fundamental misunderstanding on my part or possibly something else.
I have a modified keyboard.c that takes an arbitrary keycode via the method stroke(uint_8 keycode)
. From my app I call this method with the desired keycode (in this case 0x04) followed by 0x00 which I assume acts as a "key up" event (I assume that because the original sample alternated between 0x04 and 0x00)? What I've noticed is while this sometimes works, I get into a state where an unknown keycode is firing nonstop. If TextEdit is in the foreground the character input is the number '8'. Also, the volume on my computer gets turned up all the way and cannot be turned back down until I restart the hid daemon.
I feel like I'm missing something here, but haven't been able to figure out what exactly that is through experimentation. I'm sure you're super busy, but if you could offer some feedback on what I've done wrong with my modifications or point me in the direction of documentation that would help clear up my misunderstanding I'd appreciate it.
I'm running macOS 10.12.5. I've wired up a button in my app that makes the following c calls every time it is clicked. If you'd like to see the full project I'd be happy to zip that up and include it here as well:
stroke(0x04); stroke(0x00);
Here's my modified keyboard.c. The main difference is I broke out what I think is the one-time setup logic from the keystroke logic and made the keystroke a variable.
#include <IOKit/IOKitLib.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
unsigned char report_descriptor[] = {
0x05, 0x01, // USAGE_PAGE (Generic Desktop)
0x09, 0x06, // USAGE (Keyboard)
0xa1, 0x01, // COLLECTION (Application)
0x05, 0x07, // USAGE_PAGE (Keyboard)
0x19, 0xe0, // USAGE_MINIMUM (Keyboard LeftControl)
0x29, 0xe7, // USAGE_MAXIMUM (Keyboard Right GUI)
0x15, 0x00, // LOGICAL_MINIMUM (0)
0x25, 0x01, // LOGICAL_MAXIMUM (1)
0x75, 0x01, // REPORT_SIZE (1)
0x95, 0x08, // REPORT_COUNT (8)
0x81, 0x02, // INPUT (Data,Var,Abs)
0x95, 0x01, // REPORT_COUNT (1)
0x75, 0x08, // REPORT_SIZE (8)
0x81, 0x01, // INPUT (Cnst,Ary,Abs)
0x95, 0x05, // REPORT_COUNT (5)
0x75, 0x01, // REPORT_SIZE (1)
0x05, 0x08, // USAGE_PAGE (LEDs)
0x19, 0x01, // USAGE_MINIMUM (Num Lock)
0x29, 0x05, // USAGE_MAXIMUM (Kana)
0x91, 0x02, // OUTPUT (Data,Var,Abs)
0x95, 0x01, // REPORT_COUNT (1)
0x75, 0x03, // REPORT_SIZE (3)
0x91, 0x01, // OUTPUT (Cnst,Ary,Abs)
0x95, 0x06, // REPORT_COUNT (6)
0x75, 0x08, // REPORT_SIZE (8)
0x15, 0x00, // LOGICAL_MINIMUM (0)
0x25, 0x65, // LOGICAL_MAXIMUM (101)
0x05, 0x07, // USAGE_PAGE (Keyboard)
0x19, 0x00, // USAGE_MINIMUM (Reserved (no event indicated))
0x29, 0x65, // USAGE_MAXIMUM (Keyboard Application)
0x81, 0x00, // INPUT (Data,Ary,Abs)
0x09, 0x00, // USAGE (Reserved (no event indicated))
0x75, 0x08, // REPORT_SIZE (8)
0x95, 0x01, // REPORT_COUNT (1)
0x15, 0x00, // LOGICAL_MINIMUM (0)
0x25, 0x7f, // LOGICAL_MAXIMUM (127)
0xb1, 0x02, // FEATURE (Data,Var,Abs)
0xc0 // END_COLLECTION
};
struct keyboard_report_t {
uint8_t modifier;
uint8_t reserved;
uint8_t key_codes[6];
uint8_t reserved_bis;
};
#define SERVICE_NAME "it_unbit_foohid"
#define FOOHID_CREATE 0 // create selector
#define FOOHID_SEND 2 // send selector
#define DEVICE_NAME "Foohid Virtual KB"
#define DEVICE_SN "SN 123456"
io_connect_t service_connection = 0;
uint64_t * input;
bool setupVirtualHID() {
io_iterator_t iterator;
io_service_t service;
// 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");
return false;
}
// Iterate till success
int found = 0;
while ((service = IOIteratorNext(iterator)) != IO_OBJECT_NULL) {
ret = IOServiceOpen(service, mach_task_self(), 0, &service_connection);
if (ret == KERN_SUCCESS) {
found = 1;
break;
}
IOObjectRelease(service);
}
IOObjectRelease(iterator);
if (!found) {
printf("Unable to open IOService.\n");
return false;
}
// Fill up the input arguments.
uint32_t input_count = 8;
input = calloc(input_count, sizeof(uint64_t));
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(service_connection, FOOHID_CREATE, input, input_count, NULL, 0);
if (ret != KERN_SUCCESS) {
printf("Unable to create HID device. May be fine if created previously.\n");
}
return true;
}
void stroke(uint8_t key_code) {
// Arguments to be passed through the HID message.
struct keyboard_report_t keyboard;
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) &keyboard; // keyboard struct
send[3] = sizeof(struct keyboard_report_t); // keyboard struct len
keyboard.modifier = 0;
keyboard.key_codes[0] = key_code;
kern_return_t ret = IOConnectCallScalarMethod(service_connection, FOOHID_SEND, send, send_count, NULL, 0);
if (ret != KERN_SUCCESS) {
printf("Unable to send message to HID device.\n");
}
}
Can this project be used for simulation of external Display?
I tried downloading foohid so I can run Wjoy for my MacBook air 2013, but whenever it gets towards the end of the download it just stops and the installation ends up failing. I went to the system settings to allow installation from this source, but it still ends up not working. please help
Any way to properly install the kext file now? There's nothing under releases
I'm trying to build @mastahyeti 's U2F example, but it looks like the latest release pre-dates the example by nearly a year. It might be nice to post a new release at some point so that the U2F example works out-of-the-box.
Also, for future people that are looking to build that example note that you need another compilation flag:
gcc u2f.c -o virtual_u2f -framework IOKit -framework CoreFoundation
I'm wanting to use foohid to implement a software U2F token (U2FHID specification). In order to do this, I'd need to be able to communicate in both directions though (HID device <-> some user-land app).
I know foohid currently only implements APIs for sending data from a virtual HID device, but I'm wondering how feasible it would be to add something to the device-interface for sending data back to the virtual HID device. It seems like one could:
registerNotificationPort
on it_unbit_foohid_userclient
so virtual-HID code can register a port to receive notifications on using IOConnectSetNotificationPort
.it_unbit_foohid_device
that handles receiving reports (setReport
maybe?)mach_msg_send_from_kernel
to send reports to the port registered by the virtual-HID code when the device receives a report.Does that sound vaguely correct/possible? I'm a total kernel/driver noob here, so any advice would be appreciated.
The IOHIDDevice class provides default implementations for newVendorIDNumber, newProductIDNumber, etc. that all return zero. Because foohid doesn't override these methods, games like Elite: Dangerous, which rely on these properties to rebind joystick/keyboard inputs to in-game controls, constantly lose their bindings.
I'm using foohid as a replacement for the now-defunct (and 10.10+ incompatible) WirtualJoy in my fork of HoverPad, which does override these methods and more: https://github.com/alxn1/wjoy/blob/master/WirtualJoy/wirtual_joy_device.cpp#L194
I'm currently waiting on Apple to upgrade my cert into one with kext signing, otherwise I'd happily work on this myself. If I manage to get the cert before you implement this I'll make an attempt at a pull request, but would appreciate any thoughts you would have on how to integrate this into the User Client API.
When I run "python test_mouse.py", I get the error "TypeError: function takes exactly 2 arguments (5 given)".
I'm looking for a way to tell SmartCardServices(7)
to load a virtual smart card reader driver. For example, /usr/local/libexec/SmartCardServices/drivers/ifd-ccid.bundle/Contents/Info.plist
tells the service to load the CCID driver when a specific USB device has been recognized.
I've successfully installed the kernel extension and compiled virtual_mouse
on macOS 10.12. The program works as expected, by randomly moving the position of the mouse pointer. Unfortunately, the mouse with its vendor id/product id is not recognized by SmartCardServices
. I noticed that listing the system's USB devices (ioreg -p IOUSB -l -w 0
) doesn't list the virtual device, either.
Do you think emulating a USB device so that the system service detects it would be possible with foohid?
mitrys-iMac:foohid-py dmierkin$ sudo -H pip install foohid
Collecting foohid
Downloading foohid-0.1.tar.gz
Building wheels for collected packages: foohid
Running setup.py bdist_wheel for foohid ... done
Stored in directory: /var/root/Library/Caches/pip/wheels/8c/e2/d9/f4a9244187cf9914242d8653710bab04da2b75dcd5af6fe88f
Successfully built foohid
Installing collected packages: foohid
Successfully installed foohid-0.1
Dmitrys-iMac:foohid-py dmierkin$ sudo python ./test_list.py
Traceback (most recent call last):
File "./test_list.py", line 4, in
foohid.create("FooHID {0}".format(i), "xxx")
SystemError: unable to open it_unbit_foohid service
Hi ,
This is great project, and it's that i was looking for.
But ,I have loaded foohid.kext successfully ,after exec example (virtual mouse or keyboard),
it will reports that,
"Unable to open IOService"
My macos version is 10.13.6.
Could you help me ?
Im setting mouse.buttons = 4; that should work by pressing left button of the mouse. but nothing happens. The navigation using x and y is working properly but button clicks are not
I have a service that is currently incompatible with foohid, so I would appreciate any help in uninstalling foohid.
Ciao!
There are many OS projects and forum discussions pointing to the released package (https://github.com/unbit/foohid/releases/download/0.2.1/foohid-0.2.1.dmg) and I was wondering if it would be possible to put it back.
Not everyone can or it's able to build it from the source...
Yo hi. I'm in the process of developing my first mac app and I need to create a virtual HID keyboard so that I could send the events to the system but without intervening user input on the built-in keyboard.
I have little to no experience with C++. And I've done my app in Swift 4.2.
The question is: how do I use your library from Swift?
I've managed to google some techniques with wrapping C++ code with Objective-C++ files and creating a bridging header.
Even though I'm almost sure that this way would do this, but I'm kinda lost on how to do this quite right.
Would like to hear your guidance on how to approach this.
Or maybe you can provide a simple example and I'll learn from that and can cover the rest of calls/methods because I totally need this functionality.
The only other option besides your library is also done in C++, this one Karabiner-Elements.
To me, it seems that I have no other choice so I'll probably do this anyway, but with some help, I might be able to do this faster.
I'm getting this error when running foohid python apps:
MacBook-Air-Bartosz:foohid-py bwiklak$ python test_list.py
Traceback (most recent call last):
File "test_list.py", line 4, in
foohid.create("FooHID {0}".format(i), "xxx")
SystemError: unable to create device
Mac OS 10.11.6
Tries 1.0 and lestest version of foohid.
https://github.com/xythobuz/SerialGamepad app outputs the same problem in Console.app
In the Console.app I see:
19.10.2016 21:35:08,000 kernel[0]: CODE SIGNING: cs_invalid_page(0x10b878000): p=1612[Python] final status 0x2000800, allowing (remove VALID) page
I can't get my trainer working :(
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.