So I translate the turntables into relative movements, but the relative event handling never "centers" itself after you stop moving. This keeps the gun turret continually spinning left or right in Tron, or the mouse pointer moving left,right,up,or down in the last direction moved.

I've tried to digest how mame handles the movements internally, there's got to be a way to stop the movement.


Code
        else if (buffer[0]==0xb0) // convert midi controller message into EV_REL events
      					{
      					button_event.type = EV_REL;
						button_event.code = (buffer[1]==25) ? REL_X : (buffer[1]==24) ? REL_Y : 0;  // turntable is 25 and 24
						button_event.value = (buffer[2] >= 64) ? buffer[2]-127 : buffer[2];   //  turntable moves are signed 7 bit, really never gets higher than +/- 30 with the fastest spin I could do
						
			
					  if(write(fd, &button_event, sizeof button_event) < 0)
							{
							  perror("write");
							  return 1;
							}
						
						// send SYNC event
						
						button_event.type = EV_SYN;
						button_event.code = 0;
						button_event.value = 0;

					  if(write(fd, &button_event, sizeof button_event) < 0)
							{
							  perror("write");
							  return 1;
							}



It's interesting how x movement will stop the y movement and vice versa.


src/osd/modules/input/input_sdl.cpp

Code

                        // loop over all (track)balls
                        for (int ball = 0; ball < SDL_JoystickNumBalls(joy); ball++)
                        {
                                int itemid;

                                if (ball * 2 < INPUT_MAX_ADD_RELATIVE)
                                        itemid = ITEM_ID_ADD_RELATIVE1 + ball * 2;
                                else
                                        itemid = ITEM_ID_OTHER_AXIS_RELATIVE;

                                snprintf(tempname, sizeof(tempname), "R%d %s", ball * 2, devinfo->name());
                                devinfo->device()->add_item(tempname, (input_item_id)itemid, generic_axis_get_state<std::int32_t>, &devinfo->joystick.
balls[ball * 2]);
                                snprintf(tempname, sizeof(tempname), "R%d %s", ball * 2 + 1, devinfo->name());
                                devinfo->device()->add_item(tempname, (input_item_id)(itemid + 1), generic_axis_get_state<std::int32_t>, &devinfo->joy
stick.balls[ball * 2 + 1]);
                        }
                }

                static int event_types[] = {
                        static_cast<int>(SDL_JOYAXISMOTION),
                        static_cast<int>(SDL_JOYBALLMOTION),
                        static_cast<int>(SDL_JOYHATMOTION),
                        static_cast<int>(SDL_JOYBUTTONDOWN),
                        static_cast<int>(SDL_JOYBUTTONUP)
                };


src/emu/ioport.cpp

Code
      // relative and positional controls all map directly with a 512x scale factor
        else
        {
                // The relative code is set up to allow specifing PORT_MINMAX and default values.
                // The validity checks are purposely set up to not allow you to use anything other
                // a default of 0 and PORT_MINMAX(0,mask).  This is in case the need arises to use
                // this feature in the future.  Keeping the code in does not hurt anything.
                if (m_adjmin > m_adjmax)
                        // adjust for signed
                        m_adjmin = -m_adjmin;

                if (m_wraps)
                        m_adjmax++;

                m_minimum = (m_adjmin - m_adjdefvalue) * INPUT_RELATIVE_PER_PIXEL;
                m_maximum = (m_adjmax - m_adjdefvalue) * INPUT_RELATIVE_PER_PIXEL;

                // make the scaling the same for easier coding when we need to scale
                m_scaleneg = m_scalepos = compute_scale(1, INPUT_RELATIVE_PER_PIXEL);

                if (m_field.analog_reset())
                        // delta values reverse from center
                        m_reverse_val = 0;
                else
                {
                        // positional controls reverse from their max range
                        m_reverse_val = m_maximum + m_minimum;

                        // relative controls reverse from 1 past their max range
                        if (m_wraps)
                        {
                                // FIXME: positional needs -1, using INPUT_RELATIVE_PER_PIXEL skips a position (and reads outside the table array)
                                if(field.type() == IPT_POSITIONAL || field.type() == IPT_POSITIONAL_V)
                                        m_reverse_val --;
                                else
                                        m_reverse_val -= INPUT_RELATIVE_PER_PIXEL;
                        }
                }
        }