in-memory keybinding changes

This commit is contained in:
Matthew Berry 2021-07-18 18:25:10 -07:00
parent 2bcd5a3120
commit 40b485780c
10 changed files with 181 additions and 9 deletions

View file

@ -36,6 +36,10 @@ abstract class Controller
emu.handle_event(event)
end
def handle_input(input : Input, pressed : Bool) : Nil
emu.handle_input(input, pressed)
end
def toggle_sync : Nil
emu.toggle_sync
end

View file

@ -22,6 +22,9 @@ class StubbedController < Controller
def handle_event(event : SDL::Event) : Nil
end
def handle_input(input : Input, pressed : Bool) : Nil
end
def toggle_sync : Nil
end

View file

@ -48,9 +48,10 @@ class SDLOpenGLImGuiFrontend < Frontend
LibGL.use_program(@shader_programs[@controller.class])
@opengl_info = OpenGLInfo.new
@io = setup_imgui
LibSDL.gl_set_swap_interval(1) if @controller.class == StubbedController
@file_explorer = ImGui::FileExplorer.new
LibSDL.gl_set_swap_interval(1) if @controller.class == StubbedController
@keybindings = ImGui::Keybindings.new
end
def run : NoReturn
@ -115,11 +116,18 @@ class SDLOpenGLImGuiFrontend < Frontend
when SDL::Event::JoyHat,
SDL::Event::JoyButton then @controller.handle_event(event)
when SDL::Event::Keyboard
case event.sym
when .tab? then @controller.toggle_sync if event.pressed?
# when .m? then toggle_blending if event.pressed?
when .q? then exit 0
else @controller.handle_event(event)
if @keybindings.wants_input?
@keybindings.key_released(event.sym) unless event.pressed? # pass on key release
else
case event.sym
when .tab? then @controller.toggle_sync if event.pressed?
# when .m? then toggle_blending if event.pressed?
when .q? then exit 0
else
if input = @keybindings[event.sym]?
@controller.handle_input(input, event.pressed?)
end
end
end
else nil
end
@ -158,8 +166,9 @@ class SDLOpenGLImGuiFrontend < Frontend
overlay_height = 10.0
open_rom_selection = false
open_bios_selection = false
open_keybindings = false
if LibSDL.get_mouse_focus || @controller.class == StubbedController
if (LibSDL.get_mouse_focus || @controller.class == StubbedController) && !@file_explorer.open? && !@keybindings.open?
if ImGui.begin_main_menu_bar
if ImGui.begin_menu "File"
previously_paused = @pause
@ -169,6 +178,7 @@ class SDLOpenGLImGuiFrontend < Frontend
ImGui.menu_item "Overlay", "", pointerof(@enable_overlay)
# ImGui.menu_item "Blend", "", pointerof(@enable_blend) todo: re-implement blending now that frames are cleared
ImGui.menu_item "Pause", "", pointerof(@pause)
open_keybindings = ImGui.menu_item "Keybindings"
ImGui.end_menu
toggle_blending if @enable_blend ^ @blending
@ -185,6 +195,8 @@ class SDLOpenGLImGuiFrontend < Frontend
@file_explorer.render(:ROM, open_rom_selection, ROM_EXTENSIONS)
@file_explorer.render(:BIOS, open_bios_selection)
@keybindings.render(open_keybindings)
if @enable_overlay
ImGui.set_next_window_pos(ImGui::ImVec2.new 10, overlay_height)
ImGui.set_next_window_bg_alpha(0.5)

View file

@ -5,6 +5,12 @@ module ImGui
@selected_entry_idx = 0
@match_hidden = false
@open = false
def open? : Bool
@open
end
getter selection : Tuple(Path, Symbol)? = nil
def initialize(@path = Path[explorer_dir].expand(home: true))
@ -12,6 +18,7 @@ module ImGui
end
def render(name : Symbol, open_popup : Bool, extensions : Array(String)? = nil) : Nil
@open ||= open_popup
ImGui.open_popup(name.to_s) if open_popup
center = ImGui.get_main_viewport.get_center
ImGui.set_next_window_pos(center, ImGui::ImGuiCond::Appearing, ImGui::ImVec2.new(0.5, 0.5))
@ -51,7 +58,7 @@ module ImGui
ImGui.begin_group
open_file(name) if ImGui.button "Open"
ImGui.same_line
ImGui.close_current_popup if ImGui.button "Cancel"
close if ImGui.button "Cancel"
ImGui.same_line(spacing: 10)
ImGui.checkbox("Show hidden files?", pointerof(@match_hidden))
ImGui.end_group
@ -59,13 +66,18 @@ module ImGui
end
end
def close : Nil
@open = false
ImGui.close_current_popup
end
def clear_selection : Nil
@selection = nil
end
private def open_file(name : Symbol) : Nil
@selection = {(@path / @matched_entries[@selected_entry_idx][:name]).normalize, name}
ImGui.close_current_popup
close
set_explorer_dir @path.to_s
end

View file

@ -0,0 +1,92 @@
module ImGui
class Keybindings
POPUP_NAME = "Keybindings"
BUTTON_SIZE = ImGui::ImVec2.new(32, 0)
@open = false
@selection : Input? = nil
@keycodes : Hash(LibSDL::Keycode, Input) = {
LibSDL::Keycode::E => Input::UP,
LibSDL::Keycode::D => Input::DOWN,
LibSDL::Keycode::S => Input::LEFT,
LibSDL::Keycode::F => Input::RIGHT,
LibSDL::Keycode::K => Input::A,
LibSDL::Keycode::J => Input::B,
LibSDL::Keycode::L => Input::SELECT,
LibSDL::Keycode::SEMICOLON => Input::START,
LibSDL::Keycode::W => Input::L,
LibSDL::Keycode::R => Input::R,
}
@editing_keycodes : Hash(LibSDL::Keycode, Input) = {} of LibSDL::Keycode => Input
delegate :[]?, to: @keycodes
def initialize
overwrite_hash(@editing_keycodes, @keycodes)
end
def open? : Bool
@open
end
def wants_input? : Bool
!@selection.nil?
end
def key_released(keycode : LibSDL::Keycode) : Nil
if selection = @selection
@editing_keycodes.reject!(@editing_keycodes.key_for?(selection))
@editing_keycodes[keycode] = selection
@selection = nil
else
puts "Something went wrong when setting keybinding.."
end
end
def render(open_popup : Bool) : Nil
@open ||= open_popup
if open_popup
overwrite_hash(@editing_keycodes, @keycodes)
ImGui.open_popup(POPUP_NAME)
end
center = ImGui.get_main_viewport.get_center
ImGui.set_next_window_pos(center, ImGui::ImGuiCond::Appearing, ImGui::ImVec2.new(0.5, 0.5))
hovered_button_color = ImGui.get_style_color_vec4(ImGui::ImGuiCol::ButtonHovered)
if ImGui.begin_popup_modal(POPUP_NAME, flags: ImGui::ImGuiWindowFlags::AlwaysAutoResize)
Input.values.each do |input|
selected = @selection == input
keycode = @editing_keycodes.key_for?(input)
button_text = keycode ? String.new(LibSDL.get_key_name(keycode)) : ""
x_pos = ImGui.get_window_content_region_max.x - BUTTON_SIZE.x
ImGui.text(input.to_s)
ImGui.same_line(x_pos)
ImGui.push_style_color(ImGui::ImGuiCol::Button, hovered_button_color) if selected
if ImGui.button(button_text, BUTTON_SIZE)
@selection = input
end
ImGui.pop_style_color if selected
end
apply if ImGui.button "Apply"
ImGui.same_line
close if ImGui.button "Cancel"
ImGui.end_popup
end
end
private def apply : Nil
overwrite_hash(@keycodes, @editing_keycodes)
close
end
private def overwrite_hash(to_hash : Hash(K, V), from_hash : Hash(K, V)) : Hash(K, V) forall K, V
to_hash.clear
from_hash.each { |key, val| to_hash[key] = val }
to_hash
end
private def close : Nil
@open = false
ImGui.close_current_popup
end
end
end

12
src/crab/common/input.cr Normal file
View file

@ -0,0 +1,12 @@
enum Input
UP
DOWN
LEFT
RIGHT
A
B
SELECT
START
L
R
end

View file

@ -62,6 +62,10 @@ module GB
joypad.handle_joypad_event event
end
def handle_input(input : Input, pressed : Bool) : Nil
joypad.handle_input(input, pressed)
end
def toggle_sync : Nil
apu.toggle_sync
end

View file

@ -35,6 +35,20 @@ module GB
@direction_keys = (value >> 4) & 0x1 == 0
end
def handle_input(input : Input, pressed : Bool) : Nil
case input
in Input::UP then @up = pressed
in Input::DOWN then @down = pressed
in Input::LEFT then @left = pressed
in Input::RIGHT then @right = pressed
in Input::A then @a = pressed
in Input::B then @b = pressed
in Input::SELECT then @select = pressed
in Input::START then @start = pressed
in Input::L, Input::R then nil
end
end
def handle_joypad_event(event : SDL::Event) : Nil
case event
when SDL::Event::Keyboard

View file

@ -61,6 +61,10 @@ module GBA
keypad.handle_keypad_event event
end
def handle_input(input : Input, pressed : Bool) : Nil
keypad.handle_input(input, pressed)
end
def toggle_sync : Nil
apu.toggle_sync
end

View file

@ -54,6 +54,21 @@ module GBA
end
end
def handle_input(input : Input, pressed : Bool) : Nil
case input
in Input::UP then @keyinput.up = !pressed
in Input::DOWN then @keyinput.down = !pressed
in Input::LEFT then @keyinput.left = !pressed
in Input::RIGHT then @keyinput.right = !pressed
in Input::A then @keyinput.a = !pressed
in Input::B then @keyinput.b = !pressed
in Input::SELECT then @keyinput.select = !pressed
in Input::START then @keyinput.start = !pressed
in Input::L then @keyinput.l = !pressed
in Input::R then @keyinput.r = !pressed
end
end
def handle_keypad_event(event : SDL::Event) : Nil
case event
when SDL::Event::Keyboard