diff --git a/inc/app.h b/inc/app.h index 4fdceb037d5e54c3e0a5f78fe4e05135635af8b0..73971394e2ddd47ee720260138811405ec3ec491 100644 --- a/inc/app.h +++ b/inc/app.h @@ -13,6 +13,7 @@ G_DECLARE_FINAL_TYPE( GameApp* game_app_new(); void game_app_button_press( GameApp* app, int pin ); +void game_app_button_release( GameApp* app, int pin ); #ifdef __cplusplus } diff --git a/inc/window.h b/inc/window.h index e84493498c95e6e528bd356afc78045b227af93d..bd9804efca43fef7a66702bce4f00a0e07ab075c 100644 --- a/inc/window.h +++ b/inc/window.h @@ -15,6 +15,7 @@ G_DECLARE_FINAL_TYPE( GameWindow, GameWindow* game_window_new( GameApp* app ); void game_window_button_press( GameWindow* window, int pin ); +void game_window_button_release( GameWindow* window, int pin ); #ifdef __cplusplus } diff --git a/src/app.c b/src/app.c index 6ab728d6812ba1f2db809d198e08aee49f1eaff0..8e4dfe7c641a9a718eec90bb8535998ce0d8a19d 100644 --- a/src/app.c +++ b/src/app.c @@ -36,6 +36,12 @@ void game_app_button_press( GameApp* app, int pin ) { } +void game_app_button_release( GameApp* app, int pin ) { + + game_window_button_release( app->window, pin ); + +} + /* PRIVATE FUNK!!! */ static void game_app_class_init( GameAppClass* class ) { diff --git a/src/main.c b/src/main.c index 588c6a364132f18d4876585e3a545c24ffbfee15..5ee8f2de7c3cc12791d914ed6cd94ab504ba27ea 100644 --- a/src/main.c +++ b/src/main.c @@ -12,6 +12,8 @@ static GameApp* app = NULL; /* PROTOTYPES!!! */ +static int button_down_cb( void* pin ); +static int button_up_cb( void* pin ); static void isr_g1(); static void isr_r1(); static void isr_g2(); @@ -46,10 +48,10 @@ int main( int argc, char** argv ) { pullUpDnControl( BUTTON_G2, PUD_UP ); pullUpDnControl( BUTTON_R2, PUD_UP ); - wiringPiISR( BUTTON_G1, INT_EDGE_FALLING, &isr_g1 ); - wiringPiISR( BUTTON_R1, INT_EDGE_FALLING, &isr_r1 ); - wiringPiISR( BUTTON_G2, INT_EDGE_FALLING, &isr_g2 ); - wiringPiISR( BUTTON_R2, INT_EDGE_FALLING, &isr_r2 ); + wiringPiISR( BUTTON_G1, INT_EDGE_BOTH, &isr_g1 ); + wiringPiISR( BUTTON_R1, INT_EDGE_BOTH, &isr_r1 ); + wiringPiISR( BUTTON_G2, INT_EDGE_BOTH, &isr_g2 ); + wiringPiISR( BUTTON_R2, INT_EDGE_BOTH, &isr_r2 ); app = game_app_new(); int ret = g_application_run( G_APPLICATION( app ), argc, argv ); @@ -69,7 +71,7 @@ int main( int argc, char** argv ) { /* PRIVATE FUNK!!! */ -static int button_cb( void* pin ) { +static int button_down_cb( void* pin ) { game_app_button_press( app, *( (int*) pin ) ); @@ -77,30 +79,54 @@ static int button_cb( void* pin ) { } +static int button_up_cb( void* pin ) { + + game_app_button_release( app, *( (int*) pin ) ); + + return G_SOURCE_REMOVE; + +} + static void isr_g1() { static int pin = BUTTON_G1; - g_idle_add( &button_cb, &pin ); + if ( HIGH == digitalRead( pin ) ) { + g_idle_add( &button_up_cb, &pin ); + } else { + g_idle_add( &button_down_cb, &pin ); + } } static void isr_r1() { static int pin = BUTTON_R1; - g_idle_add( &button_cb, &pin ); + if ( HIGH == digitalRead( pin ) ) { + g_idle_add( &button_up_cb, &pin ); + } else { + g_idle_add( &button_down_cb, &pin ); + } } static void isr_g2() { static int pin = BUTTON_G2; - g_idle_add( &button_cb, &pin ); + if ( HIGH == digitalRead( pin ) ) { + g_idle_add( &button_up_cb, &pin ); + } else { + g_idle_add( &button_down_cb, &pin ); + } } static void isr_r2() { static int pin = BUTTON_R2; - g_idle_add( &button_cb, &pin ); + if ( HIGH == digitalRead( pin ) ) { + g_idle_add( &button_up_cb, &pin ); + } else { + g_idle_add( &button_down_cb, &pin ); + } } diff --git a/src/window.c b/src/window.c index 6a6e7ddf084ef80ab5531be42f79c434c5432531..f0c0a6856397573e1d77565d9aa60dddf083c280 100644 --- a/src/window.c +++ b/src/window.c @@ -9,6 +9,12 @@ /* TYPES!!! */ +struct button_state { + GameWindow* window; + bool bouncing; + bool pressed; +}; + struct _GameWindow { GtkWindow parent; @@ -35,6 +41,7 @@ struct _GameWindow { enum { RED, GREEN } colour; + struct button_state g1, r1, g2, r2; bool g1_bouncing; bool r1_bouncing; bool g2_bouncing; @@ -56,6 +63,8 @@ static void game_window_init( GameWindow* window ); static void realise( GtkWidget* widget, void* data ); +static void handle_press( GameWindow* window, int pin ); + static void draw( GtkDrawingArea* area, cairo_t* cr, int width, int height, void* data ); @@ -75,39 +84,153 @@ GameWindow* game_window_new( GameApp* app ) { void game_window_button_press( GameWindow* window, int pin ) { - bool* bouncing = NULL; + fprintf( stderr, "Pressed %d", pin ); + + struct button_state* button_state = NULL; switch ( pin ) { case BUTTON_G1: - bouncing = &window->g1_bouncing; + button_state = &window->g1; break; case BUTTON_R1: - bouncing = &window->r1_bouncing; + button_state = &window->r1; break; case BUTTON_G2: - bouncing = &window->g2_bouncing; + button_state = &window->g2; break; case BUTTON_R2: - bouncing = &window->r2_bouncing; + button_state = &window->r2; break; } - assert( NULL != bouncing ); + assert( NULL != button_state ); + + if ( button_state->bouncing ) { + fprintf( stderr, "(bouncing)\n" ); + return; + } else { + fprintf( stderr, "\n" ); + } - if ( *bouncing ) { + if ( button_state->pressed ) { return; } fprintf( stderr, "Ping %d\n", pin ); - *bouncing = true; + button_state->bouncing = true; + button_state->pressed = true; + + g_timeout_add( 200, bounce_reset, button_state ); + + handle_press( window, pin ); + +} + +void game_window_button_release( GameWindow* window, int pin ) { + + fprintf( stderr, "Rele'ed %d", pin ); + + struct button_state* button_state = NULL; + + switch ( pin ) { + + case BUTTON_G1: + button_state = &window->g1; + break; + + case BUTTON_R1: + button_state = &window->r1; + break; + + case BUTTON_G2: + button_state = &window->g2; + break; + + case BUTTON_R2: + button_state = &window->r2; + break; + + } + + assert( NULL != button_state ); + + if ( button_state->bouncing ) { + fprintf( stderr, "(bouncing)\n" ); + return; + } else { + fprintf( stderr, "\n" ); + } + + if ( !button_state->pressed ) { + return; + } + + button_state->bouncing = true; + button_state->pressed = false; + + g_timeout_add( 200, bounce_reset, button_state ); + +} + +/* PRIVATE FUNK!!! */ - g_timeout_add( 200, bounce_reset, bouncing ); +static void game_window_class_init( GameWindowClass* class ) { + + gtk_widget_class_set_template_from_resource( + GTK_WIDGET_CLASS( class ), "/xyz/tomg/game/res/window.ui" ); + gtk_widget_class_bind_template_child( + GTK_WIDGET_CLASS( class ), GameWindow, area ); + + gtk_widget_class_bind_template_callback_full( + GTK_WIDGET_CLASS( class ), "realise", + G_CALLBACK( &realise ) ); + +} + +static void game_window_init( GameWindow* window ) { + + gtk_widget_init_template( GTK_WIDGET( window ) ); + + GBytes* logo_svg = g_resources_lookup_data( + "/xyz/tomg/game/res/logo.svg", 0, NULL ); + GError* error = NULL; + const char* data = g_bytes_get_data( logo_svg, NULL ); + window->logo = rsvg_handle_new_from_data( + (const unsigned char*) data, strlen( data ), &error ); + if ( NULL != error ) { + fprintf( stderr, "%s\n", error->message ); + } + g_bytes_unref( logo_svg ); + + window->state = SPLASH; + + window->g1.window = window; + window->r1.window = window; + window->g2.window = window; + window->r2.window = window; + + gtk_drawing_area_set_draw_func( + window->area, &draw, (void*) window, NULL ); + + gtk_widget_set_cursor( GTK_WIDGET( window ), + gdk_cursor_new_from_name( "none", NULL ) ); + +} + +static void realise( GtkWidget* widget, void* data ) { + + gtk_window_fullscreen( GTK_WINDOW( widget ) ); + (void) data; + +} + +static void handle_press( GameWindow* window, int pin ) { if ( !digitalRead( BUTTON_G1 ) && !digitalRead( BUTTON_R1 ) && !digitalRead( BUTTON_G2 ) && !digitalRead( BUTTON_R2 ) ) { @@ -278,53 +401,6 @@ void game_window_button_press( GameWindow* window, int pin ) { } -/* PRIVATE FUNK!!! */ - -static void game_window_class_init( GameWindowClass* class ) { - - gtk_widget_class_set_template_from_resource( - GTK_WIDGET_CLASS( class ), "/xyz/tomg/game/res/window.ui" ); - gtk_widget_class_bind_template_child( - GTK_WIDGET_CLASS( class ), GameWindow, area ); - - gtk_widget_class_bind_template_callback_full( - GTK_WIDGET_CLASS( class ), "realise", - G_CALLBACK( &realise ) ); - -} - -static void game_window_init( GameWindow* window ) { - - gtk_widget_init_template( GTK_WIDGET( window ) ); - - GBytes* logo_svg = g_resources_lookup_data( - "/xyz/tomg/game/res/logo.svg", 0, NULL ); - GError* error = NULL; - const char* data = g_bytes_get_data( logo_svg, NULL ); - window->logo = rsvg_handle_new_from_data( - (const unsigned char*) data, strlen( data ), &error ); - if ( NULL != error ) { - fprintf( stderr, "%s\n", error->message ); - } - g_bytes_unref( logo_svg ); - - window->state = SPLASH; - - gtk_drawing_area_set_draw_func( - window->area, &draw, (void*) window, NULL ); - - gtk_widget_set_cursor( GTK_WIDGET( window ), - gdk_cursor_new_from_name( "none", NULL ) ); - -} - -static void realise( GtkWidget* widget, void* data ) { - - gtk_window_fullscreen( GTK_WINDOW( widget ) ); - (void) data; - -} - static void draw( GtkDrawingArea* area, cairo_t* cr, int width, int height, void* data ) { @@ -363,7 +439,6 @@ static void draw( GtkDrawingArea* area, cairo_t* cr, pango_layout_set_text( layout, buffer, -1 ); pango_layout_get_pixel_size( layout, &lw, &lh ); - fprintf( stderr, "Layout %s size %d, %d\n", buffer, lw, lh ); cairo_move_to( cr, 0.25 * width - lw / 2., 0.5 * height - lh / 2. ); @@ -445,7 +520,39 @@ static void set_cario_colour( cairo_t* cr, enum colour colour ) { static int bounce_reset( void* data ) { - *( (bool*) data ) = false; + struct button_state* state = (struct button_state*) data; + + state->bouncing = false; + + int button = -1; + if ( state == &( state->window->g1 ) ) { + button = BUTTON_G1; + } else if ( state == &( state->window->r1 ) ) { + button = BUTTON_R1; + } else if ( state == &( state->window->g2 ) ) { + button = BUTTON_G2; + } else if ( state == &( state->window->r2 ) ) { + button = BUTTON_R2; + } + assert( -1 != button ); + + bool pressed = ( LOW == digitalRead( button ) ); + + fprintf( stderr, "Done bouncing: %s", + pressed ? "pressed" : "released" ); + + if ( pressed != state->pressed ) { + + fprintf( stderr, " (adjusting)\n" ); + + state->pressed = pressed; + if ( pressed ) { + handle_press( state->window, button ); + } + + } else { + fprintf( stderr, "\n" ); + } return G_SOURCE_REMOVE;