libinput-rs 0.3.1

100% drop-in Rust replacement for the libinput 1.31.3 C ABI and tools
Documentation
module button_lifecycle_model
  implicit none
  private

  integer, parameter, public :: state_up = 0
  integer, parameter, public :: state_down = 1
  integer, parameter, public :: input_press = 1
  integer, parameter, public :: input_release = 2
  integer, parameter, public :: input_disconnect = 3
  integer, parameter, public :: output_silent = 0
  integer, parameter, public :: output_pressed = 1
  integer, parameter, public :: output_released = 2

  public :: step

contains

  pure subroutine step(state, input, next_state, output)
    integer, intent(in) :: state, input
    integer, intent(out) :: next_state, output

    next_state = state
    output = output_silent
    select case (input)
    case (input_press)
      if (state == state_up) then
        next_state = state_down
        output = output_pressed
      end if
    case (input_release, input_disconnect)
      if (state == state_down) then
        next_state = state_up
        output = output_released
      end if
    case default
      error stop "invalid button input"
    end select
  end subroutine step

end module button_lifecycle_model

program verify_button_lifecycle
  use button_lifecycle_model
  implicit none

  integer :: first, second, third

  do first = input_press, input_disconnect
    do second = input_press, input_disconnect
      do third = input_press, input_disconnect
        call verify_trace([first, second, third])
      end do
    end do
  end do

contains

  subroutine verify_trace(inputs)
    integer, intent(in) :: inputs(:)
    integer :: state, next_state, output, index
    integer :: presses, releases

    state = state_up
    presses = 0
    releases = 0
    do index = 1, size(inputs)
      call step(state, inputs(index), next_state, output)
      if (output == output_pressed) presses = presses + 1
      if (output == output_released) releases = releases + 1
      if (releases > presses) error stop "release without logical press"
      if (presses - releases > 1) error stop "duplicate logical press"
      if ((next_state == state_down) .neqv. (presses == releases + 1)) then
        error stop "state and output history disagree"
      end if
      state = next_state
    end do

    call step(state, input_disconnect, next_state, output)
    if (next_state /= state_up) error stop "disconnect left button held"
    if (state == state_down .and. output /= output_released) then
      error stop "disconnect failed to balance press"
    end if
  end subroutine verify_trace

end program verify_button_lifecycle