From 3a59d9cb833bcfa41f5eaa222143e763d0bd0ed3 Mon Sep 17 00:00:00 2001 From: Vicki Pfau Date: Tue, 25 Apr 2023 03:24:03 -0700 Subject: [PATCH] Res: Add script for doing fake analog input by PWM-ing the d-pad --- res/scripts/analog-interpolate.lua | 77 ++++++++++++++++++++++++++++++ 1 file changed, 77 insertions(+) create mode 100644 res/scripts/analog-interpolate.lua diff --git a/res/scripts/analog-interpolate.lua b/res/scripts/analog-interpolate.lua new file mode 100644 index 000000000..d9d985a20 --- /dev/null +++ b/res/scripts/analog-interpolate.lua @@ -0,0 +1,77 @@ +local state = {} +state.period = 4 +state.phase = 0 +state.x = 0 +state.y = 0 + +function state.update() + state.phase = state.phase + 1 + if state.phase == state.period then + state.phase = 0 + end + if state.phase == 0 then + if input.activeGamepad then + local x = input.activeGamepad.axes[1] / 30000 + local y = input.activeGamepad.axes[2] / 30000 + -- Map the circle onto a square, since we don't + -- want to have a duty of 1/sqrt(2) on the angles + local theta = math.atan(y, x) + local r = math.sqrt(x * x + y * y) + if theta < math.pi * -3 / 4 then + r = -r / math.cos(theta) + elseif theta < math.pi * -1 / 4 then + r = -r / math.sin(theta) + elseif theta < math.pi * 1 / 4 then + r = r / math.cos(theta) + elseif theta < math.pi * 3 / 4 then + r = r / math.sin(theta) + elseif theta < math.pi * 5 / 4 then + r = -r / math.cos(theta) + end + state.x = math.cos(theta) * r + state.y = math.sin(theta) * r + else + state.x = 0 + state.y = 0 + end + end +end + +function state.read() + emu:clearKeys(0xF0) + if math.floor(math.abs(state.x) * state.period) > state.phase then + if state.x > 0 then + emu:addKey(C.GB_KEY.RIGHT) + else + emu:addKey(C.GB_KEY.LEFT) + end + end + if math.floor(math.abs(state.y) * state.period) > state.phase then + if state.y > 0 then + emu:addKey(C.GB_KEY.DOWN) + else + emu:addKey(C.GB_KEY.UP) + end + end + + -- The duty cycle approach can confuse menus and the like, + -- so the POV hat setting should force a direction on + if input.activeGamepad and #input.activeGamepad.hats > 0 then + local hat = input.activeGamepad.hats[1] + if hat & C.INPUT_DIR.UP ~= 0 then + emu:addKey(C.GB_KEY.UP) + end + if hat & C.INPUT_DIR.DOWN ~= 0 then + emu:addKey(C.GB_KEY.DOWN) + end + if hat & C.INPUT_DIR.LEFT ~= 0 then + emu:addKey(C.GB_KEY.LEFT) + end + if hat & C.INPUT_DIR.RIGHT ~= 0 then + emu:addKey(C.GB_KEY.RIGHT) + end + end +end + +callbacks:add("frame", state.update) +callbacks:add("keysRead", state.read)