Jelajahi Sumber

Merge pull request #93 from OpenHMD/device-class-and-flags

Device class and flags
TheOnlyJoey 7 tahun lalu
induk
melakukan
1ee683c57a

+ 66 - 9
examples/simple/simple.c

@@ -9,6 +9,7 @@
 
 #include <openhmd.h>
 #include <stdio.h>
+#include <stdlib.h>
 
 void ohmd_sleep(double);
 
@@ -36,6 +37,11 @@ void print_infoi(ohmd_device* hmd, const char* name, int len, ohmd_int_value val
 
 int main(int argc, char** argv)
 {
+	int device_idx = 0;
+
+	if(argc > 1)
+		device_idx = atoi(argv[1]);
+
 	ohmd_context* ctx = ohmd_ctx_create();
 
 	// Probe for devices
@@ -49,14 +55,28 @@ int main(int argc, char** argv)
 
 	// Print device information
 	for(int i = 0; i < num_devices; i++){
+		int device_class = 0, device_flags = 0;
+		const char* device_class_s[] = {"HMD", "Controller", "Generic Tracker", "Unknown"};
+
+		ohmd_list_geti(ctx, i, OHMD_DEVICE_CLASS, &device_class);
+		ohmd_list_geti(ctx, i, OHMD_DEVICE_FLAGS, &device_flags);
+
 		printf("device %d\n", i);
 		printf("  vendor:  %s\n", ohmd_list_gets(ctx, i, OHMD_VENDOR));
 		printf("  product: %s\n", ohmd_list_gets(ctx, i, OHMD_PRODUCT));
-		printf("  path:    %s\n\n", ohmd_list_gets(ctx, i, OHMD_PATH));
+		printf("  path:    %s\n", ohmd_list_gets(ctx, i, OHMD_PATH));
+		printf("  class:   %s\n", device_class_s[device_class > OHMD_DEVICE_CLASS_GENERIC_TRACKER ? 4 : device_class]);
+		printf("  flags:   %02x\n",  device_flags);
+		printf("    null device:         %s\n", device_flags & OHMD_DEVICE_FLAGS_NULL_DEVICE ? "yes" : "no");
+		printf("    rotational tracking: %s\n", device_flags & OHMD_DEVICE_FLAGS_ROTATIONAL_TRACKING ? "yes" : "no");
+		printf("    positional tracking: %s\n", device_flags & OHMD_DEVICE_FLAGS_POSITIONAL_TRACKING ? "yes" : "no");
+		printf("    left controller:     %s\n", device_flags & OHMD_DEVICE_FLAGS_LEFT_CONTROLLER ? "yes" : "no");
+		printf("    right controller:    %s\n\n", device_flags & OHMD_DEVICE_FLAGS_RIGHT_CONTROLLER ? "yes" : "no");
 	}
 
-	// Open default device (0)
-	ohmd_device* hmd = ohmd_list_open_device(ctx, 0);
+	// Open specified device idx or 0 (default) if nothing specified
+	printf("opening device: %d\n", device_idx);
+	ohmd_device* hmd = ohmd_list_open_device(ctx, device_idx);
 	
 	if(!hmd){
 		printf("failed to open device: %s\n", ohmd_ctx_get_error(ctx));
@@ -80,18 +100,55 @@ int main(int argc, char** argv)
 	print_infof(hmd, "distortion k:",     6, OHMD_DISTORTION_K);
 	
 	print_infoi(hmd, "digital button count:", 1, OHMD_BUTTON_COUNT);
+	print_infoi(hmd, "control count:   ", 1, OHMD_CONTROL_COUNT);
 
-	printf("\n");
+	int control_count;
+	ohmd_device_geti(hmd, OHMD_CONTROL_COUNT, &control_count);
 
-	// Ask for n rotation quaternions
+	const char* controls_fn_str[] = { "generic", "trigger", "trigger_click", "squeeze", "menu", "home",
+		"analog-x", "analog-y", "anlog_press", "button-a", "button-b", "button-x", "button-y"};
+
+	const char* controls_type_str[] = {"digital", "analog"};
+
+	int controls_fn[64];
+	int controls_types[64];
+
+	ohmd_device_geti(hmd, OHMD_CONTROLS_FUNCTIONS, controls_fn);
+	ohmd_device_geti(hmd, OHMD_CONTROLS_TYPES, controls_types);
+	
+	printf("%-25s", "controls:");
+	for(int i = 0; i < control_count; i++){
+		printf("%s (%s)%s", controls_fn_str[controls_fn[i]], controls_type_str[controls_types[i]], i == control_count - 1 ? "" : ", ");
+	}
+
+	printf("\n\n");
+
+	// Ask for n rotation quaternions and position vectors
 	for(int i = 0; i < 10000; i++){
 		ohmd_ctx_update(ctx);
 
-		float zero[] = {.0, .1, .2, 1};
-		ohmd_device_setf(hmd, OHMD_ROTATION_QUAT, zero);
-		ohmd_device_setf(hmd, OHMD_POSITION_VECTOR, zero);
+		// this can be used to set a different zero point
+		// for rotation and position, but is not required.
+		//float zero[] = {.0, .0, .0, 1};
+		//ohmd_device_setf(hmd, OHMD_ROTATION_QUAT, zero);
+		//ohmd_device_setf(hmd, OHMD_POSITION_VECTOR, zero);
 
+		// get rotation and postition
 		print_infof(hmd, "rotation quat:", 4, OHMD_ROTATION_QUAT);
+		print_infof(hmd, "position vec: ", 3, OHMD_POSITION_VECTOR);
+
+		// read controls
+		float control_state[256];
+		ohmd_device_getf(hmd, OHMD_CONTROLS_STATE, control_state);
+
+		printf("%-25s", "controls state:");
+		for(int i = 0; i < control_count; i++)
+		{
+			printf("%f ", control_state[i]);
+		}
+		puts("");
+
+		// handle digital button events
 		print_infoi(hmd, "button event count:", 1, OHMD_BUTTON_EVENT_COUNT);
 		
 		int event_count = 0;
@@ -103,7 +160,7 @@ int main(int argc, char** argv)
 			ohmd_device_geti(hmd, OHMD_BUTTON_POP_EVENT, event);
 			printf("button %d: %s", event[0], event[1] == OHMD_BUTTON_DOWN ? "down" : "up");
 		}
-
+			
 		ohmd_sleep(.01);
 	}
 

+ 85 - 7
include/openhmd.h

@@ -63,6 +63,30 @@ typedef enum {
 	OHMD_GLSL_DISTORTION_FRAG_SRC = 1,
 } ohmd_string_description;
 
+/** Standard controls. Note that this is not an index into the control state. 
+	Use OHMD_CONTROL_TYPES to determine what function a control serves at a given index. */
+typedef enum {
+	OHMD_GENERIC        = 0,
+	OHMD_TRIGGER        = 1,
+	OHMD_TRIGGER_CLICK  = 2,
+	OHMD_SQUEEZE        = 3,
+	OHMD_MENU           = 4,
+	OHMD_HOME           = 5,
+	OHMD_ANALOG_X       = 6,
+	OHMD_ANALOG_Y       = 7,
+	OHMD_ANALOG_PRESS   = 8,
+	OHMD_BUTTON_A       = 9,
+	OHMD_BUTTON_B       = 10,
+	OHMD_BUTTON_X       = 11,
+	OHMD_BUTTON_Y       = 12,
+} ohmd_control_function;
+
+/** Control type. Indicates whether controls are digital or analog. */
+typedef enum {
+	OHMD_DIGITAL = 0,
+	OHMD_ANALOG = 1
+} ohmd_control_type;
+
 /** A collection of float value information types, used for getting and setting information with
     ohmd_device_getf() and ohmd_device_setf(). */
 typedef enum {
@@ -80,7 +104,7 @@ typedef enum {
 	    left eye of the HMD. */
 	OHMD_LEFT_EYE_GL_PROJECTION_MATRIX    =  4,
 	/** float[16] (get): A "ready to use" OpenGL style 4x4 matrix with a projection matrix for the
-	    right eye of the HMD. */
+	    right eye of the HMD. */	
 	OHMD_RIGHT_EYE_GL_PROJECTION_MATRIX   =  5,
 
 	/** float[3] (get): A 3-D vector representing the absolute position of the device, in space. */
@@ -129,23 +153,40 @@ typedef enum {
 	/** float[3] (get): Universal shader aberration coefficients (post warp scaling <r,g,b>. */
 	OHMD_UNIVERSAL_ABERRATION_K           = 21,
 
+	/** float[OHMD_CONTROL_COUNT] (get): Get the state of the device's controls. */
+	OHMD_CONTROLS_STATE                = 22,
+
 } ohmd_float_value;
 
 /** A collection of int value information types used for getting information with ohmd_device_geti(). */
 typedef enum {
-	/** int[1] (get): Physical horizontal resolution of the device screen. */
+	/** int[1] (get, ohmd_geti()): Physical horizontal resolution of the device screen. */
 	OHMD_SCREEN_HORIZONTAL_RESOLUTION     =  0,
-	/** int[1] (get): Physical vertical resolution of the device screen. */
+	/** int[1] (get, ohmd_geti()): Physical vertical resolution of the device screen. */
 	OHMD_SCREEN_VERTICAL_RESOLUTION       =  1,
 
-	/** int[1] (get): Get number of events waiting in digital input event queue. */
+	/** int[1] (get, ohmd_geti()): Get number of events waiting in digital input event queue. */
 	OHMD_BUTTON_EVENT_COUNT               =  2,
-	/** int[1] (get): Get if the there was an overflow in the event queue causing events to be dropped. */
+	/** int[1] (get, ohmd_geti()): Get if the there was an overflow in the event queue causing events to be dropped. */
 	OHMD_BUTTON_EVENT_OVERFLOW            =  3,
-	/** int[1] (get): Get the number of physical digital input buttons on the device. */
+	/** int[1] (get, ohmd_geti()): Get the number of physical digital input buttons on the device. */
 	OHMD_BUTTON_COUNT                     =  4,
-	/** int[2] (get): Performs an event pop action. Format: [button_index, button_state], where button_state is either OHMD_BUTTON_DOWN or OHMD_BUTTON_UP */
+	/** int[2] (get, ohmd_geti()): Performs an event pop action. Format: [button_index, button_state], where button_state is either OHMD_BUTTON_DOWN or OHMD_BUTTON_UP */
 	OHMD_BUTTON_POP_EVENT                 =  5,
+
+	/** int[1] (get, ohmd_geti()/ohmd_list_geti()): Gets the class of the device. See: ohmd_device_class. */
+	OHMD_DEVICE_CLASS                     =  6,
+	/** int[1] (get, ohmd_geti()/ohmd_list_geti()): Gets the flags of the device. See: ohmd_device_flags. */
+	OHMD_DEVICE_FLAGS                     =  7,
+
+	/** int[1] (get, ohmd_geti()): Get the number of analog and digital controls of the device. */
+	OHMD_CONTROL_COUNT                    =  8,
+
+	/** int[OHMD_CONTROL_COUNT] (get, ohmd_geti()): Get whether controls are digital or analog. */
+	OHMD_CONTROLS_FUNCTIONS               =  9,
+	
+	/** int[OHMD_CONTROL_COUNT] (get, ohmd_geti()): Get what function controls serve. */
+	OHMD_CONTROLS_TYPES                   =  10,
 } ohmd_int_value;
 
 /** A collection of data information types used for setting information with ohmd_set_data(). */
@@ -175,6 +216,28 @@ typedef enum {
 	OHMD_BUTTON_UP   = 1
 } ohmd_button_state;
 
+/** Device classes. */
+typedef enum 
+{
+	/** HMD device. */
+	OHMD_DEVICE_CLASS_HMD        = 0,
+	/** Controller device. */
+	OHMD_DEVICE_CLASS_CONTROLLER = 1,
+	/** Generic tracker device. */
+	OHMD_DEVICE_CLASS_GENERIC_TRACKER = 2,
+} ohmd_device_class;
+
+/** Device flags. */
+typedef enum
+{
+	/** Device is a null (dummy) device. */
+	OHMD_DEVICE_FLAGS_NULL_DEVICE         = 1,
+	OHMD_DEVICE_FLAGS_POSITIONAL_TRACKING = 2,
+	OHMD_DEVICE_FLAGS_ROTATIONAL_TRACKING = 4,
+	OHMD_DEVICE_FLAGS_LEFT_CONTROLLER     = 8,
+	OHMD_DEVICE_FLAGS_RIGHT_CONTROLLER    = 16,
+} ohmd_device_flags;
+
 /** An opaque pointer to a context structure. */
 typedef struct ohmd_context ohmd_context;
 
@@ -267,6 +330,21 @@ OHMD_APIENTRYDLL int ohmd_gets(ohmd_string_description type, const char** out);
  **/
 OHMD_APIENTRYDLL const char* OHMD_APIENTRY ohmd_list_gets(ohmd_context* ctx, int index, ohmd_string_value type);
 
+
+/**
+ * Get integer value from enumeration list index.
+ *
+ * 
+ *
+ * ohmd_ctx_probe must be called before calling ohmd_list_gets.
+ *
+ * @param ctx A (probed) context.
+ * @param index An index, between 0 and the value returned from ohmd_ctx_probe.
+ * @param type What type of value to retrieve, ohmd_int_value section for more information.
+ * @return 0 on success, <0 on failure.
+ **/
+OHMD_APIENTRYDLL int OHMD_APIENTRY ohmd_list_geti(ohmd_context* ctx, int index, ohmd_int_value type, int* out);
+
 /**
  * Open a device.
  *

+ 3 - 0
src/drv_android/android.c

@@ -233,6 +233,9 @@ static void get_device_list(ohmd_driver* driver, ohmd_device_list* list)
 
 	strcpy(desc->path, "(none)");
 
+	desc->device_class = OHMD_DEVICE_CLASS_HMD;
+	desc->device_flags = OHMD_DEVICE_FLAGS_ROTATIONAL_TRACKING;
+
 	desc->driver_ptr = driver;
 }
 

+ 3 - 2
src/drv_deepoon/deepoon.c

@@ -300,10 +300,11 @@ static void get_device_list(ohmd_driver* driver, ohmd_device_list* list)
 			strcpy(desc->vendor, "Deepoon");
 			strcpy(desc->product, "Deepoon E2");
 
-			desc->revision = 0;
+			desc->device_class = OHMD_DEVICE_CLASS_HMD;
+			desc->device_flags = OHMD_DEVICE_FLAGS_ROTATIONAL_TRACKING;
 
+			desc->revision = 0;
 			strcpy(desc->path, cur_dev->path);
-
 			desc->driver_ptr = driver;
 		}
 		cur_dev = cur_dev->next;

+ 89 - 7
src/drv_dummy/dummy.c

@@ -12,6 +12,7 @@
 
 typedef struct {
 	ohmd_device base;
+	int id;
 } dummy_priv;
 
 static void update_device(ohmd_device* device)
@@ -23,27 +24,47 @@ static int getf(ohmd_device* device, ohmd_float_value type, float* out)
 	dummy_priv* priv = (dummy_priv*)device;
 
 	switch(type){
-	case OHMD_ROTATION_QUAT: 
+	case OHMD_ROTATION_QUAT:
 		out[0] = out[1] = out[2] = 0;
 		out[3] = 1.0f;
 		break;
 
 	case OHMD_POSITION_VECTOR:
-		out[0] = out[1] = out[2] = 0;
+		if(priv->id == 0){
+			// HMD
+			out[0] = out[1] = out[2] = 0;
+		}
+		else if(priv->id == 1)
+		{
+			// Left Controller
+			out[0] = -.5f;
+			out[1] = out[2] = 0;
+		}
+		else
+		{
+			// Right Controller
+			out[0] = .5f;
+			out[1] = out[2] = 0;
+		}
 		break;
 
 	case OHMD_DISTORTION_K:
 		// TODO this should be set to the equivalent of no distortion
 		memset(out, 0, sizeof(float) * 6);
 		break;
+	
+	case OHMD_CONTROLS_STATE:
+		out[0] = .1f;
+		out[1] = 1.0f;
+		break;
 
 	default:
 		ohmd_set_error(priv->base.ctx, "invalid type given to getf (%ud)", type);
-		return -1;
+		return OHMD_S_INVALID_PARAMETER;
 		break;
 	}
 
-	return 0;
+	return OHMD_S_OK;
 }
 
 static void close_device(ohmd_device* device)
@@ -58,6 +79,8 @@ static ohmd_device* open_device(ohmd_driver* driver, ohmd_device_desc* desc)
 	if(!priv)
 		return NULL;
 	
+	priv->id = desc->id;
+	
 	// Set default device properties
 	ohmd_set_default_device_properties(&priv->base.properties);
 
@@ -70,7 +93,14 @@ static ohmd_device* open_device(ohmd_driver* driver, ohmd_device_desc* desc)
 	priv->base.properties.lens_vpos = 0.046800f;
 	priv->base.properties.fov = DEG_TO_RAD(125.5144f);
 	priv->base.properties.ratio = (1280.0f / 800.0f) / 2.0f;
+	
+	// Some buttons and axes
 	priv->base.properties.digital_button_count = 4;
+	priv->base.properties.control_count = 2;
+	priv->base.properties.controls_functions[0] = OHMD_BUTTON_A;
+	priv->base.properties.controls_functions[1] = OHMD_MENU;
+	priv->base.properties.controls_types[0] = OHMD_ANALOG;
+	priv->base.properties.controls_types[1] = OHMD_DIGITAL;
 
 	// calculate projection eye projection matrices from the device properties
 	ohmd_calc_default_proj_matrices(&priv->base.properties);
@@ -85,15 +115,67 @@ static ohmd_device* open_device(ohmd_driver* driver, ohmd_device_desc* desc)
 
 static void get_device_list(ohmd_driver* driver, ohmd_device_list* list)
 {
-	ohmd_device_desc* desc = &list->devices[list->num_devices++];
+	int id = 0;
+	ohmd_device_desc* desc;
+
+	// HMD
 
-	strcpy(desc->driver, "OpenHMD Dummy Driver");
+	desc = &list->devices[list->num_devices++];
+
+	strcpy(desc->driver, "OpenHMD Null Driver");
 	strcpy(desc->vendor, "OpenHMD");
-	strcpy(desc->product, "Dummy Device");
+	strcpy(desc->product, "HMD Null Device");
 
 	strcpy(desc->path, "(none)");
 
 	desc->driver_ptr = driver;
+
+	desc->device_flags = OHMD_DEVICE_FLAGS_NULL_DEVICE | OHMD_DEVICE_FLAGS_ROTATIONAL_TRACKING;
+	desc->device_class = OHMD_DEVICE_CLASS_HMD;
+
+	desc->id = id++;
+
+	// Left Controller
+	
+	desc = &list->devices[list->num_devices++];
+
+	strcpy(desc->driver, "OpenHMD Null Driver");
+	strcpy(desc->vendor, "OpenHMD");
+	strcpy(desc->product, "Left Controller Null Device");
+
+	strcpy(desc->path, "(none)");
+
+	desc->driver_ptr = driver;
+
+	desc->device_flags = OHMD_DEVICE_FLAGS_NULL_DEVICE | 
+		OHMD_DEVICE_FLAGS_POSITIONAL_TRACKING | 
+		OHMD_DEVICE_FLAGS_ROTATIONAL_TRACKING | 
+		OHMD_DEVICE_FLAGS_LEFT_CONTROLLER;
+
+	desc->device_class = OHMD_DEVICE_CLASS_CONTROLLER;
+
+	desc->id = id++;
+	
+	// Right Controller
+	
+	desc = &list->devices[list->num_devices++];
+
+	strcpy(desc->driver, "OpenHMD Null Driver");
+	strcpy(desc->vendor, "OpenHMD");
+	strcpy(desc->product, "Right Controller Null Device");
+
+	strcpy(desc->path, "(none)");
+
+	desc->driver_ptr = driver;
+
+	desc->device_flags = OHMD_DEVICE_FLAGS_NULL_DEVICE | 
+		OHMD_DEVICE_FLAGS_POSITIONAL_TRACKING | 
+		OHMD_DEVICE_FLAGS_ROTATIONAL_TRACKING | 
+		OHMD_DEVICE_FLAGS_RIGHT_CONTROLLER;
+
+	desc->device_class = OHMD_DEVICE_CLASS_CONTROLLER;
+
+	desc->id = id++;
 }
 
 static void destroy_driver(ohmd_driver* drv)

+ 3 - 0
src/drv_external/external.c

@@ -112,6 +112,9 @@ static void get_device_list(ohmd_driver* driver, ohmd_device_list* list)
 	strcpy(desc->product, "External Device");
 
 	strcpy(desc->path, "(none)");
+		
+	desc->device_class = OHMD_DEVICE_CLASS_HMD;
+	desc->device_flags = OHMD_DEVICE_FLAGS_ROTATIONAL_TRACKING | OHMD_DEVICE_FLAGS_POSITIONAL_TRACKING;
 
 	desc->driver_ptr = driver;
 }

+ 2 - 0
src/drv_htc_vive/vive.c

@@ -403,6 +403,8 @@ static void get_device_list(ohmd_driver* driver, ohmd_device_list* list)
 		snprintf(desc->path, OHMD_STR_SIZE, "%d", idx);
 
 		desc->driver_ptr = driver;
+		desc->device_class = OHMD_DEVICE_CLASS_HMD;
+		desc->device_flags = OHMD_DEVICE_FLAGS_ROTATIONAL_TRACKING;
 
 		cur_dev = cur_dev->next;
 		idx++;

+ 13 - 0
src/drv_nolo/nolo.c

@@ -273,6 +273,9 @@ static void get_device_list(ohmd_driver* driver, ohmd_device_list* list)
 
 			strcpy(desc->path, cur_dev->path);
 
+			desc->device_flags = OHMD_DEVICE_FLAGS_POSITIONAL_TRACKING | OHMD_DEVICE_FLAGS_ROTATIONAL_TRACKING;
+			desc->device_class = OHMD_DEVICE_CLASS_HMD;
+
 			desc->driver_ptr = driver;
 			desc->id = id++;
 
@@ -285,6 +288,11 @@ static void get_device_list(ohmd_driver* driver, ohmd_device_list* list)
 
 			strcpy(desc->path, cur_dev->path);
 
+			desc->device_flags =
+				OHMD_DEVICE_FLAGS_POSITIONAL_TRACKING |
+				OHMD_DEVICE_FLAGS_ROTATIONAL_TRACKING |
+				OHMD_DEVICE_FLAGS_RIGHT_CONTROLLER;
+
 			desc->driver_ptr = driver;
 			desc->id = id++;
 
@@ -297,6 +305,11 @@ static void get_device_list(ohmd_driver* driver, ohmd_device_list* list)
 
 			strcpy(desc->path, cur_dev->path);
 
+			desc->device_flags =
+				OHMD_DEVICE_FLAGS_POSITIONAL_TRACKING |
+				OHMD_DEVICE_FLAGS_ROTATIONAL_TRACKING |
+				OHMD_DEVICE_FLAGS_LEFT_CONTROLLER;
+
 			desc->driver_ptr = driver;
 			desc->id = id++;
 		}

+ 3 - 0
src/drv_oculus_rift/rift.c

@@ -455,6 +455,9 @@ static void get_device_list(ohmd_driver* driver, ohmd_device_list* list)
 				strcpy(desc->product, rd[i].name);
 
 				desc->revision = rd[i].rev;
+		
+				desc->device_class = OHMD_DEVICE_CLASS_HMD;
+				desc->device_flags = OHMD_DEVICE_FLAGS_ROTATIONAL_TRACKING;
 
 				strcpy(desc->path, cur_dev->path);
 

+ 3 - 0
src/drv_psvr/psvr.c

@@ -267,6 +267,9 @@ static void get_device_list(ohmd_driver* driver, ohmd_device_list* list)
 		snprintf(desc->path, OHMD_STR_SIZE, "%d", idx);
 
 		desc->driver_ptr = driver;
+		
+		desc->device_class = OHMD_DEVICE_CLASS_HMD;
+		desc->device_flags = OHMD_DEVICE_FLAGS_ROTATIONAL_TRACKING;
 
 		cur_dev = cur_dev->next;
 		idx++;

+ 33 - 3
src/openhmd.c

@@ -143,6 +143,25 @@ const char* OHMD_APIENTRY ohmd_list_gets(ohmd_context* ctx, int index, ohmd_stri
 	}
 }
 
+int OHMD_APIENTRY ohmd_list_geti(ohmd_context* ctx, int index, ohmd_int_value type, int* out)
+{
+	if(index >= ctx->list.num_devices)
+		return OHMD_S_INVALID_PARAMETER;
+
+	switch(type){
+	case OHMD_DEVICE_CLASS:
+		*out = ctx->list.devices[index].device_class;
+		return OHMD_S_OK;
+
+	case OHMD_DEVICE_FLAGS:
+		*out = ctx->list.devices[index].device_flags;
+		return OHMD_S_OK;
+
+	default:
+		return OHMD_S_INVALID_PARAMETER;
+	}
+}
+
 static unsigned int ohmd_update_thread(void* arg)
 {
 	ohmd_context* ctx = (ohmd_context*)arg;
@@ -328,10 +347,9 @@ static int ohmd_device_getf_unp(ohmd_device* device, ohmd_float_value type, floa
 	case OHMD_POSITION_VECTOR:
 	{
 		*(vec3f*)out = device->position;
-
 		for(int i = 0; i < 3; i++)
 			out[i] += device->position_correction.arr[i];
-
+		
 		return OHMD_S_OK;
 	}
 	case OHMD_UNIVERSAL_DISTORTION_K: {
@@ -445,7 +463,7 @@ int OHMD_APIENTRY ohmd_device_geti(ohmd_device* device, ohmd_int_value type, int
 		case OHMD_BUTTON_COUNT:
 			*out = device->properties.digital_button_count;
 			return OHMD_S_OK;
-
+		
 		case OHMD_BUTTON_POP_EVENT: {
 				ohmd_digital_input_event event;
 
@@ -458,6 +476,18 @@ int OHMD_APIENTRY ohmd_device_geti(ohmd_device* device, ohmd_int_value type, int
 
 				return OHMD_S_OK;
 			}
+		
+		case OHMD_CONTROL_COUNT:
+			*out = device->properties.control_count;
+			return OHMD_S_OK;
+
+		case OHMD_CONTROLS_TYPES:
+			memcpy(out, device->properties.controls_types, device->properties.control_count * sizeof(int));
+			return OHMD_S_OK;
+		
+		case OHMD_CONTROLS_FUNCTIONS:
+			memcpy(out, device->properties.controls_functions, device->properties.control_count * sizeof(int));
+			return OHMD_S_OK;
 
 		default:
 				return OHMD_S_INVALID_PARAMETER;

+ 5 - 0
src/openhmdi.h

@@ -36,6 +36,8 @@ typedef struct {
 	char path[OHMD_STR_SIZE];
 	int revision;
 	int id;
+	ohmd_device_flags device_flags;
+	ohmd_device_class device_class;
 	ohmd_driver* driver_ptr;
 } ohmd_device_desc;
 
@@ -60,6 +62,9 @@ typedef struct {
 		int hres;
 		int vres;
 		int digital_button_count;
+		int control_count;
+		int controls_functions[64];
+		int controls_types[64];
 
 		float hsize;
 		float vsize;