Controller input

If you have any questions on programming, this is the place to ask them, whether you're a newbie or an experienced programmer. Discussion on programming in general is also welcome. We will help you with programming homework, but we will not do your work for you! Any porting requests must be made in Developmental Ideas.
Post Reply
User avatar
PH3NOM
DC Developer
DC Developer
Posts: 576
https://www.artistsworkshop.eu/meble-kuchenne-na-wymiar-warszawa-gdzie-zamowic/
Joined: Fri Jun 18, 2010 9:29 pm
Has thanked: 0
Been thanked: 5 times

Controller input

Post by PH3NOM »

Hi guys, whats up?

Maybe I'm dense, but I am having some issues with the K:OS controller input functions.

Using some code based on the K:OS vorbistest.c:

Code: Select all

		if (cont_get_cond(maple_first_controller(), &cond) < 0)
			break;
		if (!(cond.buttons & CONT_START))
			x++;
By calling the function once, I would expect x to increment once if start is pressed.
However, it seems to execute multiple times. Depending on CPU load, x will increment 3-8x.

I recall someone mentioning key-up requests, but I am not sure how that works here...

Any help appreciated!
Ex-Cyber
DCEmu User with No Life
DCEmu User with No Life
Posts: 3641
Joined: Sat Feb 16, 2002 1:55 pm
Has thanked: 0
Been thanked: 0

Re: Controller input

Post by Ex-Cyber »

The condition you're detecting is "the Start button is down RIGHT NOW", not "the Start button was pressed" (which implies that it wasn't pressed at some point in the past). If you call this code periodically, it will keep incrementing as long as you hold down the Start button. If you actually are just calling it once (how?), I'm not sure what's going on. I'm guessing you probably want to do something like this:

Code: Select all

      if (cont_get_cond(maple_first_controller(), &cond) < 0)
         break;
      if (!(cond.buttons & CONT_START) && (prev_buttons & CONT_START))
         x++;
      prev_buttons = cond.buttons;
"You know, I have a great, wonderful, really original method of teaching antitrust law, and it kept 80 percent of the students awake. They learned things. It was fabulous." -- Justice Stephen Breyer
User avatar
PH3NOM
DC Developer
DC Developer
Posts: 576
Joined: Fri Jun 18, 2010 9:29 pm
Has thanked: 0
Been thanked: 5 times

Re: Controller input

Post by PH3NOM »

Thanks but what is prev_buttons in the code you posted?

And dont think too hard the code I posted is not literal, just a simplified example of my problem...
Ex-Cyber
DCEmu User with No Life
DCEmu User with No Life
Posts: 3641
Joined: Sat Feb 16, 2002 1:55 pm
Has thanked: 0
Been thanked: 0

Re: Controller input

Post by Ex-Cyber »

prev_buttons is just meant to be a variable with the same type as cond.buttons (don't know what it is off the top of my head). Where you'd declare it depends on the overall structure of the code, but assuming x is declared properly then it should be fine to declare prev_buttons in the same place.
"You know, I have a great, wonderful, really original method of teaching antitrust law, and it kept 80 percent of the students awake. They learned things. It was fabulous." -- Justice Stephen Breyer
User avatar
BlueCrab
The Crabby Overlord
The Crabby Overlord
Posts: 5663
Joined: Mon May 27, 2002 11:31 am
Location: Sailing the Skies of Arcadia
Has thanked: 9 times
Been thanked: 69 times
Contact:

Re: Controller input

Post by BlueCrab »

Also, please do not use the cont_get_cond() function in new code. It will be going away very soon. If you're using a version of KOS that has been updated any time in the past 2 years, none of the examples should use it any more (I just checked when I got rid of it it from the examples). The old Maple API has been deprecated since KOS 1.1.8 (released in 2002), so there's pretty much no reason why it should have still been around. :?

All remnants of the old Maple API will be going away within the next few days probably from the SVN, cont_get_cond() included.

For reference, the relevant replacement code in the same vorbistest.c file looks like this:

Code: Select all

		maple_device_t *cont = maple_enum_type(0, MAPLE_FUNC_CONTROLLER);

		if (cont)
		{
			cont_state_t *state = (cont_state_t *)maple_dev_status(cont);
			if(!state)
				break;
			if (state->buttons & CONT_START)
				break;
			if (state->buttons & CONT_Y)
			{
				printf("main: restarting oggvorbis\r\n");
				sndoggvorbis_stop();
				sndoggvorbis_start("/rd/test.ogg",0);
			}
			thd_sleep(10);
			bitratenew=sndoggvorbis_getbitrate();
			if (bitratenew != bitrateold)
			{
				printf("main: Vorbisfile current bitrate %ld\r\n",bitratenew);
				bitrateold = bitratenew;
			}
		}
I guess use that to adapt whatever you come up with in here...

Also, for reference, state->buttons (same as the old cond.buttons, just inverted (hence no nots in the checks)) is of type uint32. Just to actually contribute to the real topic at hand. :wink:

EDIT: And by "in the next few days", I really meant in the next 20 minutes. The old Maple API compatibility stuff is gone from the SVN of KOS as of r716.
User avatar
PH3NOM
DC Developer
DC Developer
Posts: 576
Joined: Fri Jun 18, 2010 9:29 pm
Has thanked: 0
Been thanked: 5 times

Re: Controller input

Post by PH3NOM »

Sh!ts weak, Im stuck using Dev Iso R4...

R5 sounds like its about ready?
User avatar
BlueCrab
The Crabby Overlord
The Crabby Overlord
Posts: 5663
Joined: Mon May 27, 2002 11:31 am
Location: Sailing the Skies of Arcadia
Has thanked: 9 times
Been thanked: 69 times
Contact:

Re: Controller input

Post by BlueCrab »

PH3NOM wrote:Sh!ts weak, Im stuck using Dev Iso R4...
The DC Dev ISO R4 has r561 of KOS from the SVN. It supports the new Maple API just fine, so that code I posted will work fine (all SVN versions of KOS would support it, as would released versions 1.1.8, 1.1.9, and 1.2.0).
R5 sounds like its about ready?
I wouldn't have any idea whatsoever, as I wasn't actually directly involved in making it. I don't use Windows, so I haven't ever even used it at all. It all depends on when someone steps up to make such a thing.
User avatar
PH3NOM
DC Developer
DC Developer
Posts: 576
Joined: Fri Jun 18, 2010 9:29 pm
Has thanked: 0
Been thanked: 5 times

Re: Controller input

Post by PH3NOM »

Thanks BlueCrab, I forgot to include <dc/maple.h> after that it worked.

But I still dont quite follow how to trigger only on key-up.
Here is what I'm working with now; It works, but the entire process is blocked while the start button is pressed.

What is the best way to do this?

Code: Select all

void mouse_input2( struct pvr_frame_vertex *button_vertex, struct mouse_frame *mouse ) {
 
     maple_device_t *cont = maple_enum_type(0, MAPLE_FUNC_CONTROLLER);    
    
     if (cont) {
               
        cont_state_t *state = (cont_state_t *)maple_dev_status(cont);
         
        if(!state)
           return 0;

        // Controls for moving the mouse cursor
		if (state->buttons & CONT_DPAD_RIGHT) {
	       if( mouse->x <= DISPLAY_WIDTH - 26 )
               mouse->x+=4;
        }
		if (state->buttons & CONT_DPAD_LEFT) {
	       if( mouse->x >= 4 )
               mouse->x-=4;
        }
        if (state->buttons & CONT_DPAD_DOWN) {        
           if( mouse->y <= DISPLAY_HEIGHT - 32)
              mouse->y+=4;
        }
        if (state->buttons & CONT_DPAD_UP) {        
           if( mouse->y >= 4)
              mouse->y-=4;
        }
      
        // Controls for selecting highlighted item            
        if(state->buttons & CONT_START) {
         
           if( mouse->x >= button_vertex[0].left && mouse->x <= button_vertex[0].right &&
               mouse->y <= button_vertex[0].bottom && mouse->y >= button_vertex[0].top) {
           
               while(state->buttons & CONT_START) {
                   thd_sleep(1);
               }
               printf("Launch Video browser\n");
           }    
           else if( mouse->x >= button_vertex[1].left && mouse->x <= button_vertex[1].right &&
               mouse->y <= button_vertex[1].bottom && mouse->y >= button_vertex[1].top) {
               
               while(state->buttons & CONT_START) {
                   thd_sleep(1);
               }
               printf("Launch Music browser\n");
           }    
           else if( mouse->x >= button_vertex[2].left && mouse->x <= button_vertex[2].right &&
               mouse->y <= button_vertex[2].bottom && mouse->y >= button_vertex[2].top) {
               
               while(state->buttons & CONT_START) {
                   thd_sleep(1);
               }
               printf("Launch Photo browser\n");
           }
           else if( mouse->x >= button_vertex[3].left && mouse->x <= button_vertex[3].right &&
               mouse->y <= button_vertex[3].bottom && mouse->y >= button_vertex[3].top) {
               
               while(state->buttons & CONT_START) {
                   thd_sleep(1);
               }
               printf("Launch Binary browser\n");                       
           }    
        }    
     }     
}
Ex-Cyber
DCEmu User with No Life
DCEmu User with No Life
Posts: 3641
Joined: Sat Feb 16, 2002 1:55 pm
Has thanked: 0
Been thanked: 0

Re: Controller input

Post by Ex-Cyber »

I would recommend having a struct (or class) that embodies an abstract version of the input you're interested in (i.e. not the actual bits of the Dreamcast controller/mouse, but unpacked into elements like confirm button, cancel button, start/pause button, normalized cursor position/deltas, etc.) factor out all of the controller/mouse code into a function that does nothing except update that struct (or object), and check that abstract state in the main loop of your program. It's a really bad idea to make decisions about high-level program flow inside the guts of a controller-reading function.

edit: I know this isn't really what you asked, but I think it's at the root of the problem you're experiencing right now. It's a more general problem of organizing a program. You don't want to get stuck in some obscure function that isn't clearly intended to stop the program, or have the high-level state of the program implicitly change somewhere in the murkiest depths of the call graph. It makes maintenance and debugging a complete nightmare.
"You know, I have a great, wonderful, really original method of teaching antitrust law, and it kept 80 percent of the students awake. They learned things. It was fabulous." -- Justice Stephen Breyer
User avatar
RyoDC
Mental DCEmu
Mental DCEmu
Posts: 366
Joined: Wed Mar 30, 2011 12:13 pm
Has thanked: 2 times
Been thanked: 0

Re: Controller input

Post by RyoDC »

Why do we need this code?

Code: Select all

         cont_state_t *state = (cont_state_t *)maple_dev_status(cont);
         if(!state)
            break;
Is it might be something wrong with the device?
How do I try to build a Dreamcast toolchain:
Image
Ex-Cyber
DCEmu User with No Life
DCEmu User with No Life
Posts: 3641
Joined: Sat Feb 16, 2002 1:55 pm
Has thanked: 0
Been thanked: 0

Re: Controller input

Post by Ex-Cyber »

It's because maple_dev_status returns a pointer, which can be NULL (if the device passed to it is invalid). Dereferencing NULL is generally a bad idea (Dan Potter actually did it once to demo MMU support by mapping the framebuffer to address 0x00000000, but that was basically done as a joke and shouldn't be taken as a proper example).
"You know, I have a great, wonderful, really original method of teaching antitrust law, and it kept 80 percent of the students awake. They learned things. It was fabulous." -- Justice Stephen Breyer
Chilly Willy
DC Developer
DC Developer
Posts: 414
Joined: Thu Aug 20, 2009 11:00 am
Has thanked: 0
Been thanked: 2 times

Re: Controller input

Post by Chilly Willy »

Take all the DC stuff out of the picture... make a separate function called something like get_buttons(). Then your code would be like:

Code: Select all

    current_buttons = get_buttons();
    changed_buttons = current_buttons ^ previous_buttons;
    previous_buttons = current_buttons;

    if (changed_buttons & SOME_BUTTON)
    {
        // SOME_BUTTON has changed!
        if (current_buttons & SOME_BUTTON)
        {
            // SOME_BUTTON has just been pressed
        }
        else
        {
            // SOME_BUTTON has just been released
        }
    }
User avatar
PH3NOM
DC Developer
DC Developer
Posts: 576
Joined: Fri Jun 18, 2010 9:29 pm
Has thanked: 0
Been thanked: 5 times

Re: Controller input

Post by PH3NOM »

Thanks for the help guys, I think i have implemented most of your suggestions.

What I'm working on is a GUI...

Here is the controller input function Im currently using, and it works great!

Let me know if you guys see any issues...

Code: Select all

void mouse_input2( struct pvr_frame_vertex *button_vertex, struct mouse_frame *mouse ) {
 
     maple_device_t *cont = maple_enum_type(0, MAPLE_FUNC_CONTROLLER);    
    
     if (cont) {
               
        cont_state_t *state = (cont_state_t *)maple_dev_status(cont);
         
        if(!state)
           return 0;

        // Controls for moving the mouse cursor
		if (state->buttons & CONT_DPAD_RIGHT) {
	       if( mouse->x <= DISPLAY_WIDTH )
               mouse->x+=4;
        }
		if (state->buttons & CONT_DPAD_LEFT) {
	       if( mouse->x >= 4 )
               mouse->x-=4;
        }
        if (state->buttons & CONT_DPAD_DOWN) {        
           if( mouse->y <= DISPLAY_HEIGHT)
              mouse->y+=4;
        }
        if (state->buttons & CONT_DPAD_UP) {        
           if( mouse->y >= 4)
              mouse->y-=4;
        }
      
        // Controls for selecting highlighted item            
        if(state->buttons & CONT_START) {
           if( mouse->x >= button_vertex[0].left && mouse->x <= button_vertex[0].right &&
               mouse->y <= button_vertex[0].bottom && mouse->y >= button_vertex[0].top)            
               mouse->start[0] = 1;    
           else if( mouse->x >= button_vertex[1].left && mouse->x <= button_vertex[1].right &&
               mouse->y <= button_vertex[1].bottom && mouse->y >= button_vertex[1].top) 
               mouse->start[1] = 1; 
           else if( mouse->x >= button_vertex[2].left && mouse->x <= button_vertex[2].right &&
               mouse->y <= button_vertex[2].bottom && mouse->y >= button_vertex[2].top)
               mouse->start[2] = 1;
           else if( mouse->x >= button_vertex[3].left && mouse->x <= button_vertex[3].right &&
               mouse->y <= button_vertex[3].bottom && mouse->y >= button_vertex[3].top) 
               mouse->start[3] = 1;                       
        }    
     }     
}
And the caller function works like this:

Code: Select all

// Our structure for user input via the mouse simulator
struct mouse_frame controller;

// Main menu - Check for user input then draw the menu
int main_menu() {
    
    int cell = 0;
	
    while(1) { 
        // Check for controller input, adjusting the mouse pointer in the process
        mouse_input2( button_vertex, &controller );
        
        // If the mouse pointer is over a button polygon, highlight it and set the background
        if( controller.x >= button_vertex[0].left && controller.x <= button_vertex[0].right &&
            controller.y <= button_vertex[0].bottom && controller.y >= button_vertex[0].top)
            cell = 0;
        else if( controller.x >= button_vertex[1].left && controller.x <= button_vertex[1].right &&
                 controller.y <= button_vertex[1].bottom && controller.y >= button_vertex[1].top)
            cell = 1;
        else if( controller.x >= button_vertex[2].left && controller.x <= button_vertex[2].right &&
                 controller.y <= button_vertex[2].bottom && controller.y >= button_vertex[2].top)
            cell = 2;
        else if( controller.x >= button_vertex[3].left && controller.x <= button_vertex[3].right &&
                 controller.y <= button_vertex[3].bottom && controller.y >= button_vertex[3].top)
            cell = 3; 

        // If the mouse pointer is over a button polygon and start is pressed, launch the selected menu
        if( controller.start[0]  ) {
            controller.start[0] = 0;
            video_menu();
        }
        else if ( controller.start[1] ) {
            controller.start[1] = 0;
            music_menu();
        }
        else if ( controller.start[2] ) {
            controller.start[2] = 0;
            photo_menu();
        }        
        else if ( controller.start[3] ) {
            controller.start[3] = 0;
            app_menu();
        }    
User avatar
RyoDC
Mental DCEmu
Mental DCEmu
Posts: 366
Joined: Wed Mar 30, 2011 12:13 pm
Has thanked: 2 times
Been thanked: 0

Re: Controller input

Post by RyoDC »

Well, if really, logic is seems quite difficult.

Oh, now I get. Well I had a few improvement ideas on that, i'll post it few hours later.

My vision of this stuff:

Code: Select all

int CheckCondition(pvr_frame_vertex *button_vertex, mouse_frame* mouse)
{
    if( mouse->x >= button_vertex[0].left && mouse->x <= button_vertex[0].right &&
          mouse->y <= button_vertex[0].bottom && mouse->y >= button_vertex[0].top)
          return(0);
    else if( mouse->x >= button_vertex[1].left && mouse->x <= button_vertex[1].right &&
          mouse->y <= button_vertex[1].bottom && mouse->y >= button_vertex[1].top)
          return(1);
    else if( mouse->x >= button_vertex[2].left && mouse->x <= button_vertex[2].right &&
          mouse->y <= button_vertex[2].bottom && mouse->y >= button_vertex[2].top)
          return(2);
    else if( mouse->x >= button_vertex[3].left && mouse->x <= button_vertex[3].right &&
          mouse->y <= button_vertex[3].bottom && mouse->y >= button_vertex[3].top)
         return(3);
}


void mouse_input2(pvr_frame_vertex *button_vertex, mouse_frame *mouse)
{

    maple_device_t *cont = maple_enum_type(0, MAPLE_FUNC_CONTROLLER);
    //pluggin' the first controller of the dreamcast
    if(cont) //checkin the condition
    {
        //if true...
     cont_state_t *state = (cont_state_t *)maple_dev_status(cont);

        if(!state)
           return 0;//if fails return 0 exit code

        // Controls for moving the mouse cursor
      if (state->buttons & CONT_DPAD_RIGHT)
       {
          if( mouse->x <= DISPLAY_WIDTH )
               mouse->x+=4;
       }
      if (state->buttons & CONT_DPAD_LEFT)
       {
          if( mouse->x >= 4 )
               mouse->x-=4;//just move cursor left on the
               //4 pixels yeah? seems strange
        }
        if (state->buttons & CONT_DPAD_DOWN)
        {
           if( mouse->y <= DISPLAY_HEIGHT)
              mouse->y+=4;//so we set it above the max value of
              //possible height value, isn't it?
        }
        if (state->buttons & CONT_DPAD_UP) {
           if( mouse->y >= 4)
              mouse->y-=4;//...
        }

        // Controls for selecting highlighted item
        if(state->buttons & CONT_START)
        {
            int i = CheckCondition(&mouse);
            switch(i)
            {
                case 0:
                    mouse->start[0]  =1;
                    break;
                case 1:
                    mouse->start[1]  =1;
                    break;
                case 2:
                    mouse->start[2]  =1;
                    break;
                case 3:
                    mouse->start[3]  =1;
                    break;
                default: break;

            }
        }
    }
}





How do I try to build a Dreamcast toolchain:
Image
Post Reply