Beispiel #1
0
int
ui_joystick_init( void )
{
  const char *home;
  char *calibration;
  int error;

  home = compat_get_home_path(); if( !home ) return 1;

  /* Default calibration file is ~/.joystick */
  calibration = malloc( strlen( home ) + strlen( JSDefaultCalibration ) + 2 );

  if( !calibration ) {
    ui_error( UI_ERROR_ERROR, "failed to initialise joystick: %s",
	      "not enough memory" );
    return 0;
  }

  sprintf( calibration, "%s/%s", home, JSDefaultCalibration );

  /* If we can't init the first, don't try the second */
  error = open_joystick( 0, settings_current.joystick_1, calibration );
  if( error ) return 0;

  error = open_joystick( 1, settings_current.joystick_2, calibration );
  if( error ) return 1;

  return 2;
}
/* a little test program */
int main(int argc, char *argv[])
{
  int fd, rc;
  int done = 0;

  struct js_event jse;

  fd = open_joystick();

  if (fd < 0) 
  {
    perror("open_joystick");
    exit(1);
  }


  while (!done) {
    rc = read_joystick_event(&fd, &jse);
    usleep(1000);

    if (rc == 1) 
    {
      printf("Event: time %8u, value %8hd, type: %3u, axis/button: %u\n", 
             jse.time, jse.value, jse.type, jse.number);
    }
  }
}
int wykryj_joystick() {
joystick_fd = open_joystick(joystick_descriptor);
if (joystick_fd < 0) {
printf("Nie wykryto joysticka %s\n", joystick_descriptor);
if (pierwsze_wykrywanie_joysticka == TRUE) {
gtk_toggle_button_set_active(check_button_joystick, FALSE);
g_signal_connect(check_button_joystick, "clicked",
G_CALLBACK(toggle_joystick_button_callback), NULL);
/* FIXME */
}
} else {
printf("Wykryto joystick %s\n", joystick_descriptor);
if (pierwsze_wykrywanie_joysticka == TRUE) {
gtk_toggle_button_set_active(check_button_joystick, TRUE);
g_signal_connect(check_button_joystick, "clicked",
G_CALLBACK(toggle_joystick_button_callback), NULL);
}
ioch = g_io_channel_unix_new(joystick_fd);
int iowatch = -1;
iowatch = g_io_add_watch(ioch, G_IO_IN, zczytuj_joystick, NULL);

if (get_ready_to_rumble(rumbledevice) != 0) {
printf("No rumble...\n");
}
}
pierwsze_wykrywanie_joysticka = FALSE;
}
void joystick_linux::enumerate_joysticks(udev *p_udev) {

	udev_enumerate *enumerate;
	udev_list_entry *devices, *dev_list_entry;
	udev_device *dev;

	enumerate = udev_enumerate_new(p_udev);
	udev_enumerate_add_match_subsystem(enumerate,"input");
	udev_enumerate_add_match_property(enumerate, "ID_INPUT_JOYSTICK", "1");

	udev_enumerate_scan_devices(enumerate);
	devices = udev_enumerate_get_list_entry(enumerate);
	udev_list_entry_foreach(dev_list_entry, devices) {

		const char* path = udev_list_entry_get_name(dev_list_entry);
		dev = udev_device_new_from_syspath(p_udev, path);
		const char* devnode = udev_device_get_devnode(dev);

		if (devnode) {

			String devnode_str = devnode;
			if (devnode_str.find(ignore_str) == -1) {
				joy_mutex->lock();
				open_joystick(devnode);
				joy_mutex->unlock();
			}
		}
		udev_device_unref(dev);
	}
	udev_enumerate_unref(enumerate);
}
Axis*
SDLDriver::create_axis(const FileReader& reader, Control* parent)
{
  if (reader.get_name() == "sdl:joystick-axis")
  {
    JoystickAxisBinding binding;

    reader.read_int("device", binding.device);
    reader.read_int("axis",   binding.axis);
      
    if (open_joystick(binding.device))
    {
      binding.binding = new Axis(parent);
      joystick_axis_bindings.push_back(binding);
      
      return binding.binding;
    }
    else
    {
      return 0;
    }
  }
  else
  {
    return 0;
  }
}
Beispiel #6
0
void * JoystickPollingLoop(void *ptr )
{
    int fd, rc;

	struct js_event jse;

	fd = open_joystick(joystick_device);
	if (fd < 0)
	{
		printf("joystick open failed.\n");
		STOP_JOYSTICK_THREAD=1;
		return 0;
	}

   JOYSTICK_OK=1;
   while ( !STOP_JOYSTICK_THREAD )
     {

		rc = read_joystick_event(&jse);
		usleep(1000);
		if (rc == 1)
		 {
			//printf("Event: time %8u, value %8hd, type: %3u, axis/button: %u\n",jse.time, jse.value, jse.type, jse.number);
            HandleJoystickEvent(&jse);

		 }

     }
  JOYSTICK_OK=0;


  return 0;
}
int
main (void)
{
  if (open_joystick ("/dev/js0"))
    if (open_joystick ("/dev/input/js0"))
      {
	printf ("RobotOption %i 1\n", USE_NON_BLOCKING);
	puts ("Name Joybot_Analog");
	puts ("Colour C2ED42 42EDC2");
	fflush (stdout);
	fprintf (stderr, "Exiting joystick bot ...\n");
	sleep (3);
	puts ("Print Could not open the joystick device, exiting ...");
	return -1;
      }
  printf ("RobotOption %i 1\n", USE_NON_BLOCKING);
  fflush (stdout);
  main_loop ();
}
void joystick_linux::monitor_joysticks(udev *p_udev) {

	udev_device *dev = NULL;
	udev_monitor *mon = udev_monitor_new_from_netlink(p_udev, "udev");
	udev_monitor_filter_add_match_subsystem_devtype(mon, "input", NULL);
	udev_monitor_enable_receiving(mon);
	int fd = udev_monitor_get_fd(mon);

	while (!exit_udev) {

		fd_set fds;
		struct timeval tv;
		int ret;

		FD_ZERO(&fds);
		FD_SET(fd, &fds);
		tv.tv_sec = 0;
		tv.tv_usec = 0;

		ret = select(fd+1, &fds, NULL, NULL, &tv);

		/* Check if our file descriptor has received data. */
		if (ret > 0 && FD_ISSET(fd, &fds)) {
			/* Make the call to receive the device.
			   select() ensured that this will not block. */
			dev = udev_monitor_receive_device(mon);

			if (dev && udev_device_get_devnode(dev) != 0) {

				joy_mutex->lock();
				String action = udev_device_get_action(dev);
				const char* devnode = udev_device_get_devnode(dev);
				if (devnode) {

					String devnode_str = devnode;
					if (devnode_str.find(ignore_str) == -1) {

						if (action == "add")
							open_joystick(devnode);
						else if (String(action) == "remove")
							close_joystick(get_joy_from_path(devnode));
					}
				}

				udev_device_unref(dev);
				joy_mutex->unlock();
			}
		}
		usleep(50000);
	}
	//printf("exit udev\n");
	udev_monitor_unref(mon);
}
Beispiel #9
0
int main(int argc, char** argv)
{
    glutInit(&argc,argv);
    glutInitWindowPosition(0,0);
    glutInitWindowSize(800,600);
    glutInitDisplayMode(GLUT_DOUBLE|GLUT_RGBA);
    glutCreateWindow("PewPew");
    //glEnable(GL_LIGHTING);
    glEnable(GL_LINE_SMOOTH);
    glEnable(GL_BLEND);
    //glShadeModel(GL_SMOOTH);
    //glEnable(GL_LIGHT0);
    glMatrixMode(GL_PROJECTION);

    open_joystick();

    mn.add_option(std::string("INFO"),(&info_action));
    mn.add_option(std::string("PLAY"),(&run));
    mn.add_option(std::string("NEW GAME"),(&new_game));
    mn.add_option(std::string("OPTIONS"),(&option_action));
    mn.add_option(std::string("QUIT"),(&end_0));

    menu_pages.push(&mn);

    opt.add_option(std::string("BACK"),(&back));
    opt.add_option(std::string("SCORES"),(&scores_action));
    opt.add_option(std::string("SOUNDS ON"),(&sound_off),std::string("SOUNDS OFF"),(&sound_on));

    scores.add_option(std::string("BACK"), (&back));

    info.add_option(std::string("BACK"),(&back));

    //GLfloat filter[11] = {0.3,0.28,0.26,0.24,0.22,0.20,0.22,0.24,0.26,0.28,0.3};	//GOOD
    //glSeparableFilter2D(GL_SEPARABLE_2D, GL_LUMINANCE, 11, 11, GL_LUMINANCE, GL_FLOAT, filter,filter); //<< segfault !!!

    //glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
    glHint(GL_LINE_SMOOTH_HINT, GL_DONT_CARE);
    glutReshapeFunc(reshape);
    glutDisplayFunc(display);
    //glutIdleFunc(mytimer);
    glutTimerFunc(20,mytimer,1);

    glutIgnoreKeyRepeat(1);
    glutKeyboardUpFunc(kbRelF);
    glutSpecialFunc(skbF);
    glutKeyboardFunc(kbF);
    glutPassiveMotionFunc(mIdleF);
    glutMouseFunc(mF);
    glutMainLoop();

    return 0;
}
Beispiel #10
0
void joystick_linux::monitor_joysticks() {

	while (!exit_udev) {
		joy_mutex->lock();
		for (int i = 0; i < 32; i++) {
			char fname[64];
			sprintf(fname, "/dev/input/event%d", i);
			if (attached_devices.find(fname) == -1) {
				open_joystick(fname);
			}
		}
		joy_mutex->unlock();
		usleep(1000000); // 1s
	}
}
Beispiel #11
0
void spektrum_satellite_init (void) {
	
	int32_t i;
	for (i=0; i<16; i++) {
		sat.channels[i]=-500;
		channel_center[i]=0;
		joystick_axes[i]=0;
		joystick_buttons[i]=0;
		joy_max[i]=32700;
		joy_min[i]=-32700;
	}
	sat.channels[RC_THROTTLE]=0;
	channel_center[RC_YAW]=0;
	joystick_filedescriptor=open_joystick(JOYSTICK_DEVICE);
	last_update=time_keeper_get_millis();
	
	#ifdef KEYBOARD_ACTIVE
	set_conio_terminal_mode();
	#endif
}
int main(int argc, char *argv[]){
    unsigned char stop, temp;
    unsigned char cmd;
    unsigned char arg1, arg2;
    char arg1buf[4], arg2buf[4];
    packet recievepkt;
    packet sendpkt;


    int fd_joy;			// File Descriptor for joystick
	int temp1;
	struct js_event e;
	temp1 = 0;               // Set first time stamp to zero
	fd_joy = open_joystick();   // /Initalize the joystick
   // printf("fd_joy: %d\n", fd_joy);


    strncpy(device, argv[1], DEVICE_MAX_SIZE);

    //set up serial port
    if((fd = configDevice()) < 2){
        perror("Error opening/configuring device\n");
        return -1;
        }

    menu();

    //set handler for close command
    signal(SIGUSR2, catchClose);
    signal(SIGTERM, catchClose);

    //create timer for ping
    pid = fork();
    if (pid < 0) printf("Error creating ping timer process\n");
    else if(pid == 0){
        //die if parent dies
        prctl(PR_SET_PDEATHSIG, SIGHUP);
        //set alarm for ping timeout
        signal(SIGALRM, sendPing);
        //prime Timeout reset handler
        signal(SIGUSR1, catchTimeoutReset);

        alarm(PING_INTERVAL);

        for(timeouts = 0; timeouts < PING_RETRIES;){
            //spin wheels. exit if ping timeout occurs
        }
        //kill parent process if ping timeout
        printf("Ping timeout. %d unanswered pings\n", timeouts);
        //tell parent to exit
        kill(getppid(), SIGKILL);
        return 1;
    }

    int readcount;
    char zeroflag;


    //main control loop
    for(stop = 0; stop <= 0;){

        //cmd = 'V';
        //arg1 = 0;
        //arg2 = 0;
        /*scanf("%c %s %s%c", &cmd, arg1buf, arg2buf, NULL);        //get command
        //strcpy(arg1buf, "Z");
        arg1 = (unsigned char)atoi(arg1buf);
        arg2 = (unsigned char)atoi(arg2buf);

        if(arg1 == 0){
            arg1 = 1;
        }
        if(arg2 == 0){
            arg2 = 1;
        }*/

        readcount = read (fd_joy, &e, sizeof(e));
		//printf("servo: %d\r", e.time);
        //printf("bytes read from joystick: %d\n", readcount);
		//if(e.time > temp1)
		{
            //printf("Bryan\n");
			if(e.type == 1 && e.value == 1){
                if(e.time > temp1){
                    button_press(e.number);
                    temp1 = e.time;
                    }
				}
			if(e.type == 2 /*&& e.value != 0*/){
			if(!zeroflag){
				axis_press(e.number, e.value);
				}
			//set zeroflag if event input zero
			//necessary to not keep resending packages
			//when in the zero (stopped) position
            zeroflag = (e.value == 0) ? 1 : 0;
            //printf("zeroflag %c\n", zeroflag);
            }
		}

        //while((temp = getchar()) != '\n' && temp != EOF);  //clear buffer
        //printf("CMD: %c ARG1: %c ARG2: %c\n", cmd, arg1, arg2);
        //stop = parseCommand(cmd, arg1, arg2);
    }
    close(fd);
    //tell child to exit
    kill(pid, SIGUSR2);
    t1.join();
    scanf("", NULL);
    return 0;
}
Beispiel #13
0
int main(int argc, char **argv) {
	//int sockfd;
	int portno, n;
	struct sockaddr_in serveraddr;
  //const struct sockaddr serveraddr;
	struct hostent *server;
	char *hostname;
	char buf[BUFSIZE];
	char message[BUFSIZE];
	char* param[3];
	int cont = 0;

	/* All below is joystick stuff */
	bool joystickControl = false;
	int command; /*command type for agv*/
	int comaddr; /*addr for command to go*/
	int comval; /*value of command*/

	/* True only if an event we are using is activated */
	bool relevant = true;

	int fd, rc;
	int done = 0;

	/* Data types for threads */
	pthread_t joyThread;
	thdata joyData; // this is a structure we can pass to the thread
	//pthread_t heartbeat_thread;
	//thdata heartData;

	/* This is trapping the Ctrl-C signal for safe shutdown */
	signal(SIGINT, INThandler);

	/* Create the joystick polling thread */
	pthread_create(&joyThread, NULL, (void *) &joystick_update, (void *) &joyData);
	/* Create the client heartbeat thread */
	//pthread_create(&heartbeat_thread, NULL, (void *) &heartbeatCheck, (void *) &heartData);

	// FIXME If no joystick, don't just die
	fd = open_joystick(0);
	if (fd < 0) {
		printf("open failed.\n");
		//exit(1);
	}

/* check command line arguments */
if (argc != 3) {
  fprintf(stderr,"usage: %s <hostname> <port>\n", argv[0]);
  exit(0);
}

	while(cont == 0)
	{
		// Why are we doing argument checking and
		// socket stuff inside a while loop?
		// this may be causing the excessivs file open
		// errors we are having

		/* FIXME - THIS SECTION SHOULD BE OUTSIDE OF while() LOOP */
		/* ****************************************************** */

		hostname = argv[1];
		portno = atoi(argv[2]);

		/* socket: create the socket */
		sockfd = socket(AF_INET, SOCK_STREAM, 0);
		if (sockfd < 0)
		error("ERROR opening socket");
		
		/* gethostbyname: get the server's DNS entry */
		server = gethostbyname(hostname);
		if (server == NULL) {
		fprintf(stderr,"ERROR, no such host as %s\n", hostname);
		exit(0);
		}
		
		/* build the server's Internet address */
		bzero((char *) &serveraddr, sizeof(serveraddr));
		serveraddr.sin_family = AF_INET;
		bcopy((char *)server->h_addr,
		(char *)&serveraddr.sin_addr.s_addr, server->h_length);
		serveraddr.sin_port = htons(portno);


		/* ****************************************************** */
		/* FIXME - THIS SECTION SHOULD BE OUTSIDE OF while() LOOP */
    //I think I was just able to pull it out of loop
    //except for this part
                /*Connect: create a connection with the server*/
                if (connect(sockfd, &serveraddr, sizeof(serveraddr)) < 0)
                {
                        error("ERROR connecting");
                }
    
    
		bzero(buf, BUFSIZE);

		if (!joystickControl) {
			/* get message line from the user */
			printf("Please enter msg: ");
			fgets(buf, BUFSIZE, stdin);
		}
		else {
			usleep(125000);
			if (relevant) {
				joy_x = scale_joystick(joystick_x);
				joy_y = -scale_joystick(joystick_y);
				joy_z = scale_joystick(joystick_z);
				sprintf(buf, "15 %d %d %d\n", joy_x, joy_y, joy_z);
			}
		}
		/*
		 * Copy the buffer to message array which will be evaluated
		 * to determine if joystick control is being done
		 * message will contain whatever we sent as the message
		 * (i dont think we need this anymore)
		 */
		strcpy(message, buf);

		param[0] = strtok(message, " ");
		param[1] = strtok(NULL, " ");
		param[2] = strtok(NULL, "\0");
		command = atoi(param[0]); // we always have this

		/*
		 * This code is here to insure that we react properly to the
		 * number of bytes sent. If a variable assignment is made
		 * using a nul pointer, the program will segfault
		 */
		 // do we have a 2nd parameter (address)
		if (param[1] != NULL)	{
			comaddr = atoi(param[1]);
		}
		// do we have a 3rd parameter (value)
		if (param[2] != NULL)	{
			comval = atoi(param[2]);
		}

		/* Are we under joystick control */
		if (fire_pressed == true || command == 9) {
			joystickControl = true;
			printf("Fire pressed: %d\n", fire_pressed);
			printf("Command: %d\n", command);
		}
		else
		{
			if(joystickControl == true)
			{
				sprintf(buf, "9 0\n");
				printf("turning wheels off\n");
			}
			joystickControl = false;
		}

		/*
		 *Check to see if we're killing the client
		 */
		if(strcmp(buf, "99\n") == 0)
		{
			cont = 1;
      }

		/* send the message line to the server */
		n = write(sockfd, buf, strlen(buf));
		if (n < 0)
			error("ERROR writing to socket");

		/* print the server's reply */
		bzero(buf, BUFSIZE);
		n = read(sockfd, buf, BUFSIZE);
		if(buf == NULL)
		{
			buf == "\n";
		}
		if (n < 0)
			error("ERROR reading from socket");
		printf("Echo from server: %s\n", buf);
	}
	close(sockfd);
    return 0;
}
Beispiel #14
0
int joy_open_handler(const char *path, const char *types, lo_arg **argv, int argc,
		 void *data, void *user_data)
{
  printf("sdl2osc: joystick open handler\n");
  open_joystick( argv[0]->i );
}
Beispiel #15
0
Button*
SDLDriver::create_button(const FileReader& reader, Control* parent)
{
  //log_info("SDL: " << reader.get_name());
  if (reader.get_name() == "sdl:joystick-button")
  {
    JoystickButtonBinding binding;

    reader.read_int("device", binding.device);
    reader.read_int("button", binding.button);
      
    if (open_joystick(binding.device))
    {
      binding.binding = new Button(parent);
      joystick_button_bindings.push_back(binding);
      
      return binding.binding;
    }
    else
    {
      return 0;
    }
  }
  else if (reader.get_name() == "sdl:mouse-button")
  {
    MouseButtonBinding binding;

    reader.read_int("button", binding.button);
    binding.binding = new Button(parent);
    mouse_button_bindings.push_back(binding);

    return binding.binding;
  }
  else if (reader.get_name() == "sdl:keyboard-button")
  {
    std::string key;
    if (reader.read_string("key", key)) 
    {
      String2Key::iterator i = string2key.find(key);
      if (i != string2key.end()) 
      {
        KeyboardButtonBinding binding;
      
        binding.key = i->second;
        binding.binding = new Button(parent);
        keyboard_button_bindings.push_back(binding);

        return binding.binding;
      }
      else 
      {
        log_error("couldn't find keysym for key '" << key << "'");
        return 0;
      }
    }
    else
    {
      log_error("'key' missing");
      return 0;
    }
  }
  else
  {
    return 0;
  }
}
/**************************************************************************
 *                              driver_joyGetDevCaps
 */
LRESULT driver_joyGetDevCaps(DWORD_PTR device_id, JOYCAPSW* caps, DWORD size)
{
    joystick_t* joystick;
    IOHIDDeviceRef device;

    if ((joystick = joystick_from_id(device_id)) == NULL)
        return MMSYSERR_NODRIVER;

    if (!open_joystick(joystick))
        return JOYERR_PARMS;

    caps->szPname[0] = 0;

    device = IOHIDElementGetDevice(joystick->element);
    if (device)
    {
        CFStringRef product_name = IOHIDDeviceGetProperty(device, CFSTR(kIOHIDProductKey));
        if (product_name)
        {
            CFRange range;

            range.location = 0;
            range.length = min(MAXPNAMELEN - 1, CFStringGetLength(product_name));
            CFStringGetCharacters(product_name, range, (UniChar*)caps->szPname);
            caps->szPname[range.length] = 0;
        }
    }

    caps->wMid = MM_MICROSOFT;
    caps->wPid = MM_PC_JOYSTICK;
    caps->wXmin = 0;
    caps->wXmax = 0xFFFF;
    caps->wYmin = 0;
    caps->wYmax = 0xFFFF;
    caps->wZmin = 0;
    caps->wZmax = joystick->axes[AXIS_Z].element ? 0xFFFF : 0;
    caps->wNumButtons = CFArrayGetCount(joystick->buttons);
    if (size == sizeof(JOYCAPSW))
    {
        int i;

        /* complete 95 structure */
        caps->wRmin = 0;
        caps->wRmax = 0xFFFF;
        caps->wUmin = 0;
        caps->wUmax = 0xFFFF;
        caps->wVmin = 0;
        caps->wVmax = 0xFFFF;
        caps->wMaxAxes = 6; /* same as MS Joystick Driver */
        caps->wNumAxes = 0;
        caps->wMaxButtons = 32; /* same as MS Joystick Driver */
        caps->szRegKey[0] = 0;
        caps->szOEMVxD[0] = 0;
        caps->wCaps = 0;

        for (i = 0; i < NUM_AXES; i++)
        {
            if (joystick->axes[i].element)
            {
                caps->wNumAxes++;
                switch (i)
                {
                    case AXIS_Z:  caps->wCaps |= JOYCAPS_HASZ; break;
                    case AXIS_RX: caps->wCaps |= JOYCAPS_HASU; break;
                    case AXIS_RY: caps->wCaps |= JOYCAPS_HASV; break;
                    case AXIS_RZ: caps->wCaps |= JOYCAPS_HASR; break;
                }
            }
        }

        if (joystick->hatswitch)
            caps->wCaps |= JOYCAPS_HASPOV | JOYCAPS_POV4DIR;
    }

    TRACE("name %s buttons %u axes %d caps 0x%08x\n", debugstr_w(caps->szPname), caps->wNumButtons, caps->wNumAxes, caps->wCaps);

    return JOYERR_NOERROR;
}
Beispiel #17
0
/* a little test program */
int main(int argc, char *argv[])
{
	int  joy_file, received, serial_file;
	int  done = 0;
	char joy_address[32] = "/dev/input/\0";
	int  axis_values[8] = {0};
	int  button_values[11] = {0};

	struct js_event jse;

	if(argc > 2)
	{
		printf("Too many arguments, exiting.");
		return 0;
	}
	if(argc == 2)
	{
		strcat(joy_address, argv[1]);
		joy_file = open_joystick(joy_address);
	}
	else if(argc == 1)
	{
		joy_file = open_joystick("/dev/input/js0");
	}
	
	if (joy_file < 0) 
	{
		printf("Joystick open failed.\n");
		exit(1);
	}

	serial_file = serialport_init(ARDUINO_COMM_LOCATION, ROBOT_BAUDRATE);
	
	if(serial_file < 0)
	{
		printf("Can't open serial port.");
		exit(2);
	}

	clearPort(serial_file);

	while (!done) {
		received = read_joystick_event(&jse);
		usleep(1000);
		if (received == 1) {
			switch(jse.type)
			{
				case TYPE_NOT_BUTTON:
					if(axis_values[jse.number] != jse.value)
						axis_values[jse.number] = jse.value;
					break;	
				case TYPE_BUTTON:
					if(button_values[jse.number] != jse.value)
					{
						button_values[jse.number] = jse.value;
						send_button_update(&jse, serial_file);
					}
					break;
			}	
		}
	}
}
/**************************************************************************
 *                              driver_joyGetPosEx
 */
LRESULT driver_joyGetPosEx(DWORD_PTR device_id, JOYINFOEX* info)
{
    static const struct {
        DWORD flag;
        off_t offset;
    } axis_map[NUM_AXES] = {
        { JOY_RETURNX, FIELD_OFFSET(JOYINFOEX, dwXpos) },
        { JOY_RETURNY, FIELD_OFFSET(JOYINFOEX, dwYpos) },
        { JOY_RETURNZ, FIELD_OFFSET(JOYINFOEX, dwZpos) },
        { JOY_RETURNU, FIELD_OFFSET(JOYINFOEX, dwUpos) },
        { JOY_RETURNV, FIELD_OFFSET(JOYINFOEX, dwVpos) },
        { JOY_RETURNR, FIELD_OFFSET(JOYINFOEX, dwRpos) },
    };

    joystick_t* joystick;
    IOHIDDeviceRef device;
    CFIndex i, count;
    IOHIDValueRef valueRef;
    long value;

    if ((joystick = joystick_from_id(device_id)) == NULL)
        return MMSYSERR_NODRIVER;

    if (!open_joystick(joystick))
        return JOYERR_PARMS;

    device = IOHIDElementGetDevice(joystick->element);

    if (info->dwFlags & JOY_RETURNBUTTONS)
    {
        info->dwButtons = 0;
        info->dwButtonNumber = 0;

        count = CFArrayGetCount(joystick->buttons);
        for (i = 0; i < count; i++)
        {
            IOHIDElementRef button = (IOHIDElementRef)CFArrayGetValueAtIndex(joystick->buttons, i);
            IOHIDDeviceGetValue(device, button, &valueRef);
            value = IOHIDValueGetIntegerValue(valueRef);
            if (value)
            {
                info->dwButtons |= 1 << i;
                if (!info->dwButtonNumber)
                    info->dwButtonNumber = i + 1;
            }
        }
    }

    for (i = 0; i < NUM_AXES; i++)
    {
        if (info->dwFlags & axis_map[i].flag)
        {
            DWORD* field = (DWORD*)((char*)info + axis_map[i].offset);
            if (joystick->axes[i].element)
            {
                IOHIDDeviceGetValue(device, joystick->axes[i].element, &valueRef);
                value = IOHIDValueGetIntegerValue(valueRef) - joystick->axes[i].min_value;
                *field = MulDiv(value, 0xFFFF, joystick->axes[i].max_value - joystick->axes[i].min_value);
            }
            else
            {
                *field = 0;
                info->dwFlags &= ~axis_map[i].flag;
            }
        }
    }

    if (info->dwFlags & JOY_RETURNPOV)
    {
        if (joystick->hatswitch)
        {
            IOHIDDeviceGetValue(device, joystick->hatswitch, &valueRef);
            value = IOHIDValueGetIntegerValue(valueRef);
            if (value >= 8)
                info->dwPOV = JOY_POVCENTERED;
            else
                info->dwPOV = value * 4500;
        }
        else
        {
            info->dwPOV = 0;
            info->dwFlags &= ~JOY_RETURNPOV;
        }
    }

    TRACE("x: %d, y: %d, z: %d, r: %d, u: %d, v: %d, buttons: 0x%04x, pov %d, flags: 0x%04x\n",
          info->dwXpos, info->dwYpos, info->dwZpos, info->dwRpos, info->dwUpos, info->dwVpos, info->dwButtons, info->dwPOV, info->dwFlags);

    return JOYERR_NOERROR;
}