User File #6048250720926158

Upload All User Files

#6048250720926158 - Lua script for lsnes: Handle mouse axis.

lsnes_BasicMouseHandler_v1a.lua
System: Super Nintendo Entertainment System
780 downloads
Uploaded 4/21/2013 8:47 AM by FatRatKnight (see all 245)
At the moment, lsnes doesn't have a lot of ways to deal with certain analog inputs, such as the x- and y-axis of the mouse. This gives you a way to do that without tearing out your hair.
Would be great if anyone plans to TAS a mouse-using SNES game on lsnes.
After running the script, click around on the main window and figure it out for yourself. Can be run even on top of another script you have running, and the display of the older script will remain intact, though at the moment, this script will negate the other script's on_input and on_keyhook functions if it has either one. Sorry about that.
For lsnes only. Will not work in other emulators. Minor update because I forgot to remove a line. Before, it spams errors on every paint! Whoopsie.
--Leeland Kirwan (FatRatKnight)
--I feel this can be handled with better elegance. ... Hey, it works.

--[[
Helps in handling the mouse when TASing a game that uses it. Actually, will
also work while unpaused, if you like doing things that way.

Click anywhere on the game screen. As long as you're holding a mouse button
down, the script will let the new position of your mouse decide what the input
to lsnes will be. Will not actually determine the actual clicks of the
simulated mouse, that's up to your L or R hotkeys.

While a mouse button is held, will also display nifty feedback on what it will
do. Just try it out and see for yourself. Safe to run even if you haven't told
lsnes your movie uses a mouse or two.
]]--

local function Limits(v,l,h) return math.min(h,math.max(l,v)) end
-- Returns v, or l if it's below that, or h if above.
-- No attempt at defining behavior when h < l; Returns h, though.


--         x x y y     Mouse Input: Xmouse1, Xmouse2, Ymouse1, Ymouse2
local MI= {0,0,0,0} -- Not elegantly handled when catching user mouse.
local function ClearMI() for i= 1,4 do MI[i]= 0 end end

--*****************************************************************************
function on_input(IsSubframe)
--*****************************************************************************
--Applies input. Makes sure not to try mouse input with no mouse.
--Not currently compliant running over a script that uses on_input.

    for port= 1, 2 do  -- Whole reason why MI is a table.
        if input.port_type(port) == "mouse" then
            input.set2(port,0,0,MI[port  ])
            input.set2(port,0,1,MI[port+2])
        end
    end

    ClearMI()
end


local Mx , My= 0 , 0
local click= false

--*****************************************************************************
local function Str4(num)
--*****************************************************************************
--Just produces a + or - preceeding a three-digit decimal value.
    local s= "+"
    if num < 0 then s= "-"; num= -num end
    return string.format(s .. "%3d", num)
end

local color= 0x00FF00
--*****************************************************************************
local function ShowMouse(port)
--*****************************************************************************
-- For use with on_paint. Needs to know which port to report.
-- Paints coordinates in some top corner, and a visual line for user sanity.
-- Warns if the port isn't a mouse.

    local ResX,ResY= gui.resolution()
    local X= (ResX-72)*(port-1)      -- Paint position
    local Dx,Dy= MI[port],MI[port+2] -- Current input to send to lsnes

    gui.line(Mx,My,Mx-Dx,My-Dy,color)
    gui.crosshair(Mx   ,My   ,10,gui.rainbow(1,2,color))
    gui.crosshair(Mx-Dx,My-Dy,10,gui.rainbow(1,2,color))
    color= gui.rainbow(1,12,color)
-- Whoops! Extra color change if both mouse buttons are held. ... Don't care.

    gui.text(X,0,string.format("%s:%s",Str4(Dx),Str4(Dy)),0xFFFFFF,0x80000000)

    if input.port_type(port) ~= "mouse" then           -- Warning.
        gui.text(X,16,"No mouse!",0xFF8000,0x80000000)
    end
end

OldPaint= on_paint or function() end  -- Do not break old display script!

--*****************************************************************************
function on_paint(non_synth)
--*****************************************************************************
    OldPaint(non_synth)  -- Run old display (or null function)
    if clickL then ShowMouse(1) end
    if clickR then ShowMouse(2) end
end

local Keys= {}  -- Fill with functions to read user input.

--These next two functions track where the mouse is going.
--If the user's mouse has a button held down, will also
--adjust the Mouse Input table accordingly.
--I feel like I've done a sloppy job here. It works, though.
-------------------------------------------------------------------------------
function Keys.mouse_x(key,T) -- Mouse move X.
-------------------------------------------------------------------------------
    if clickL then MI[1]= Limits(MI[1] + T.last_rawval - Mx,-127,127) end
    if clickR then MI[2]= Limits(MI[2] + T.last_rawval - Mx,-127,127) end
    Mx= T.last_rawval
end
-------------------------------------------------------------------------------
function Keys.mouse_y(key,T) -- Mouse move Y.
-------------------------------------------------------------------------------
    if clickL then
        MI[3]= Limits(MI[3] + T.last_rawval - My,-127,127)
        gui.repaint()
    end
    if clickR then
        MI[4]= Limits(MI[4] + T.last_rawval - My,-127,127)
        gui.repaint()
    end
    My= T.last_rawval
end

-------------------------------------------------------------------------------
function Keys.mouse_left(key,T) -- Left mouse button
-------------------------------------------------------------------------------
    clickL= (T.last_rawval == 1)  -- I want true or false, not 0 or 1.
    gui.repaint()
end
-------------------------------------------------------------------------------
function Keys.mouse_right(key,T) -- Right mouse button
-------------------------------------------------------------------------------
    clickR= (T.last_rawval == 1)  -- Do I need to explain again?
    gui.repaint()
end

-------------------------------------------------------------------------------
function Keys.space(key,T)  ClearMI(); gui.repaint()  end -- Clears mouse input
-------------------------------------------------------------------------------
--Whoops, clears it in both press and release. ... Eh, whatever.

--*****************************************************************************
function on_keyhook(key,T)
--*****************************************************************************
-- Just call the individual key function. Don't ask, just do.
    Keys[key](key,T)
end
for k, v in pairs(Keys) do input.keyhook(k,true) end