0

I want my Android application to create a fake virtual device, to achieve this the device needs to be rooted and uinput module is needed.

I am using the following code to create the device, calling

static{ System.loadLibrary("myModule"); }
CreateVirtualDevice("Devname",0x123,0x123);

inside my java code. Here the native code:

#include <string.h>
#include <jni.h>
#include <fcntl.h>

#include <linux/input.h>
#include <linux/uinput.h>

static int fd;
static struct uinput_user_dev dev;

short int analog_axis_list[] = { ABS_X,ABS_Y,ABS_RX,ABS_RY, -1};

jint Java_com_example_app_MyClass_CreateVirtualDevice(
        JNIEnv* env, jobject thiz, jstring param, jint param2, jint param3) {

    int i;

    memset(&dev, 0, sizeof(dev));
    fd = open("/dev/uinput", O_WRONLY | O_NONBLOCK);
    if (fd < 0)
        return -1;
    if(ioctl(fd, UI_SET_EVBIT, EV_ABS)<0) return -4;


    for(i=0;analog_axis_list[i]>=0;i++){
        if(ioctl(fd,UI_SET_ABSBIT,analog_axis_list[i])<0) return -5;
        dev.absmax[analog_axis_list[i]]=32767;
        dev.absmin[analog_axis_list[i]]=-32768;
    }

    const char *cparam = (*env)->GetStringUTFChars(env, param, 0);
    snprintf(dev.name, UINPUT_MAX_NAME_SIZE, cparam);
    (*env)->ReleaseStringUTFChars(env, param, cparam);
    dev.id.bustype = BUS_VIRTUAL;
    dev.id.vendor = param2;
    dev.id.product = param3;
    dev.id.version = 1;

    if (write(fd, &dev, sizeof(dev)) < 0)
        return -7;

    if (ioctl(fd, UI_DEV_CREATE) < 0)
        return -8;
    return 0;

}

The device is successfully created, and the return value is 0. Inside input.h the ABS values are so defined:

#define ABS_X  0x00
#define ABS_Y  0x01
#define ABS_RX 0x03
#define ABS_RY 0x04

But when checking the axis on android, I get proper values for AXIS_X and AXIS_Y, but ABS_RX and ABS_RY have wrong values. I used this code to check the axis values:

InputDevice device = InputDevice.getDevice(ids[position]);
List<InputDevice.MotionRange> ranges = device.getMotionRanges();
StringBuilder sb = new StringBuilder("");
if(ranges.size()==0){
    sb.append("NO_MOTION_RANGES");
}
else{
    int i = 0;
    for(InputDevice.MotionRange range:ranges) {
        if(i>0) {
            sb.append(",");
        }
        sb.append(MotionEvent.axisToString(range.getAxis()));
        sb.append("(").append(range.getAxis()).append(")");
        i++;
    }
}
return sb.toString();

And the result is:

AXIS_X(0),AXIS_Y(1),AXIS_Z(11),AXIS_RZ(14)

I am using the latest NDK release (r10d) without any particular settings enabled. What can cause these errors?

I want to point out that it's my code to have something wrong, because with an actual controller the axis numbers are correct.

Edit 1: I tried to return analog_axis_list[2], which is ABS_RX, at the end of my function instead of 0 and it returns 3, so I think I'm passing a wrong type to the ioctl call. Which type should I choose?

Vektor88
  • 4,841
  • 11
  • 59
  • 111
  • ***[ioctl()](http://man7.org/linux/man-pages/man2/ioctl.2.html)*** is prototyped: `int ioctl(int d, unsigned long request, ...);`. But you have not taken advantage of looking at the return value in most, if not all of your code snippet. Try that to make sure the values (arguments) are are registering correctly. – ryyker Dec 09 '14 at 22:46
  • @ryyker I added a check on all the ioctl calls, the function returns 0. – Vektor88 Dec 10 '14 at 08:22

1 Answers1

0

Android uses AXIS_Z and AXIS_RZ for the right stick; this is consistent with USB HID.

j__m
  • 9,392
  • 1
  • 32
  • 56