Search code examples
cncurseswindows-terminalpdcurses

detection of mouse hovering using pdcurses


I am making an implemintation of conway's game of life using c and wanted to make the game highlight the cell the mouse in hovering over but i can't seem to be able to catch mouse movements even though i used ALL_MOUSE_EVENTS and MOUSE_MOVED flags

here is the input handling code :

void handle_mouse_input(){
    MEVENT event;

    if(nc_getmouse(&event) != OK) return ;
    
    if(event.x >= Play_Start_X && event.x <= Play_End_X && event.y == Play_Y){

        Pause = !Pause;

    }else if(event.x >= Exit_Start_X && event.x <= Exit_End_X && event.y == Exit_Y){
        quit();
    }else if(event.x >= State_Start_X && event.y >= State_Start_Y && event.x <= State_End_X && event.y <= State_End_Y){
        lock_state();

        cell_state new_state = alive;
        unsigned x = ((event.x - State_Start_X) / 2) + X_Indent , y = event.y - State_Start_Y + Y_Indent;
        if(lookup_cell_state(Board , x , y , false) == alive){
            new_state = dead;
        }

        set_cell(Board , x , y , new_state);

        unlock_state();
    }else if(event.x >= Reset_Start_X && event.x <= Reset_End_X && event.y == Reset_Y){
        reset_board(Board);
    }
}

//the purpose of making the function of this type is to be used with pthreads
void *handle_input(void *arg){
    if(stdscr == NULL) pthread_exit(NULL);

    keypad(stdscr , true);
    mousemask(ALL_MOUSE_EVENTS | REPORT_MOUSE_POSITION , NULL);
    mouseinterval(0);
    noecho();
    int ch = 0;

    while(1){
        pthread_mutex_lock(&IO_Mutex);

        ch = getch();

        pthread_mutex_unlock(&IO_Mutex);

        if(ch == ERR){
            continue;
        }

        if(ch == KEY_MOUSE){
            handle_mouse_input();
        }else{
            handle_keyboard_input(ch);
        }

        flushinp();
    };

    return NULL;
}

I am running this on windows terminal

note : i am testing if i catch the mouse movement using a debugger thats why i didn't write an if statement to check for bstate yet


Solution

  • i found a solution(kind of)

    here is the new code:

    void handle_mouse_input(int ch){
        MEVENT event;
        static int Last_X = -1 , Last_Y = -1;
    
        if(getmouse(&event) != OK) return ;
    
        if(event.x != Last_X || event.y != Last_Y){
            unhighlight_exit_button();
            unhighlight_play_pause_button();
            unhighlight_reset_button();
            unhighlight_cells();
    
            if(event.x >= Play_Start_X && event.x <= Play_End_X && event.y == Play_Y){
                highlight_play_pause_button();
            }else if(event.x >= Exit_Start_X && event.x <= Exit_End_X && event.y == Exit_Y){
                highlight_exit_button();
            }else if(event.x >= State_Start_X && event.y >= State_Start_Y && event.x <= State_End_X && event.y <= State_End_Y ){
                unsigned x = (event.x - State_Start_X) / 2 , y = event.y - State_Start_Y;
                highlight_cell(x , y);
    
                render_state(Board , stdscr , State_Start_X , State_Start_Y , State_End_X , State_End_Y);
                refresh();
            }else if(event.x >= Reset_Start_X && event.x <= Reset_End_X && event.y == Reset_Y){
                highlight_reset_button();
            }
        }
    
        Last_X = event.x;
        Last_Y = event.y;
    
        if(ch != KEY_MOUSE) return ;
    
        if(event.x >= Play_Start_X && event.x <= Play_End_X && event.y == Play_Y){
            Pause = !Pause;
        }else if(event.x >= Exit_Start_X && event.x <= Exit_End_X && event.y == Exit_Y){
            quit();
        }else if(event.x >= State_Start_X && event.y >= State_Start_Y && event.x <= State_End_X && event.y <= State_End_Y ){
            lock_state();
            cell_state new_state = alive;
            unsigned x = ((event.x - State_Start_X) / 2) + X_Indent , y = event.y - State_Start_Y + Y_Indent;
            if(lookup_cell_state(Board , x , y , false) == alive){
                new_state = dead;
            }
            set_cell(Board , x , y , new_state);
            unlock_state();
    
            render_state(Board , stdscr , State_Start_X , State_Start_Y , State_End_X , State_End_Y);
            refresh();
        }else if(event.x >= Reset_Start_X && event.x <= Reset_End_X && event.y == Reset_Y){
            reset_board(Board);
        }
    }
    
    //the purpose of making the function of this type is to be used with pthreads
    void *handle_input(void *arg){
        if(stdscr == NULL) return NULL;
    
        int ch = 0;
    
        ch = getch();
    
        handle_mouse_input(ch);
        
        if(ch == ERR){
            return NULL;
        }
    
        if(ch != KEY_MOUSE){
            handle_keyboard_input(ch);
        }
    
        flushinp();
    
        return NULL;
    }
    

    even though the windows terminal won't report movement , the position of the mouse is always updated even if no new event happens , so i handle the mouse input even if a mouse event didn't happen get the mouse event check its position to know which cell or button it is hovering over then check if a mouse event has happened

    you can also implement a function that detects mouse movement by getting the new mouse position then comparing it to older the position

    eg:

    
    bool mouse_moved(int *new_x , int *new_y){
        static int x = -1 , y = -1;
        
        if(new_x == NULL || new_y == NULL) return false;
    
        MEVENT event;
        nc_getmouse(&event);
    
        *new_x = -1;
        *new_y = -1;
        if(event.x != x || event.y != y){
            *new_x = x = event.x;
            *new_y = y = event.y;
    
            return true;
        }
    
        return false
    }
    
    

    EDIT : turns out this only works with pdcurses