Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Game controller not recognized #660

Open
mufty opened this issue Mar 5, 2024 · 10 comments
Open

Game controller not recognized #660

mufty opened this issue Mar 5, 2024 · 10 comments

Comments

@mufty
Copy link

mufty commented Mar 5, 2024

Just found some issue within hashlink regarding recognition of "non standard" controllers. Been trying to make a game that would use my HOTAS controller. It hashlink doesn't seem to recognize what that is. It works on the web in javascript. Tried the Pad sample from Heaps and on the web version the pad is recognized.

vivaldi_ydpd8qRuRM

In hashlink it never calls the hxd.Pad.wait callback.

LtAwzjD45h

This might be a Heaps issue though I didn't find anything there that would point to it cuz there seems to not be much regarding controller recognition it just plugs into whatever is under. So came to a conclusion it's something with Hashlink or SDL not sure which one of the two.

I'd try to work around this if we had access to raw DirectInput but we don't.

@ncannasse
Copy link
Member

ncannasse commented Mar 5, 2024 via email

@mufty
Copy link
Author

mufty commented Mar 5, 2024

I tried both directx and SDL they do the same thing

@ncannasse
Copy link
Member

I guess it's not related to Heaps then as you should at least get some feedback from SDL ?

@mufty
Copy link
Author

mufty commented Mar 6, 2024

Yeah it should that's why I think it's hashlink or the communication with libsdl.

It could be because of how the controllers are being mapped and used. There is a list of mappings in GameController

static var DEFAULTS = [

It does look a little like anything that's not on that list might be ignored but I don't know the full context of it.

@ncannasse
Copy link
Member

ncannasse commented Mar 7, 2024 via email

@mufty
Copy link
Author

mufty commented Mar 7, 2024

Oh I see SDL has gamepad and joysticks split into two different things. With different events for each of them ie. SDL_GameController* and SDL_Joystick*

@mufty
Copy link
Author

mufty commented Mar 7, 2024

In Heaps the Pad object uses only the GameController not the Joystick part so that's why the wait callback is never triggered for a joystick like device because it's not a gamepad in SDL. So now the question is how do I get access to the joystick instead of a gamepad in Heaps? Seems that there is no support in Heaps for joystick then at least not that I can see. It would require the equivalent to hxd.Pad but one that would use sdl.Joystick instead of sdl.GameController.

@mufty
Copy link
Author

mufty commented Mar 7, 2024

I should be able to mimic what Pad does for GameController and try to do something similar for Joystick. But I guess that's out of topic for a hashlink issue then. I'll still let you know if I find out something. It's just kinda hashlink adjacent because it's visible only when using SDL not when using something else like the web environment etc.

@mufty
Copy link
Author

mufty commented Mar 7, 2024

A very hacked up test for the theory... this works for opengl it's a copy of the hxd.Pad object from Heaps.

It doesn't help for directx that still has some other issue and I didn't research how it handles joysticks if it's similar to SDL or no.

package tools;

class Joystick {

    public var index : Int = -1;
    public var connected(default, null) = true;
    public var values : Array<Float> = [];
    public var buttons : Array<Bool> = [];
    public var prevValues : Array<Float> = [];
    public var xAxis(get,never) : Float;
    public var yAxis(get,never) : Float;
    public var rxAxis(get,never) : Float;
    public var ryAxis(get,never) : Float;
    public var axisDeadZone : Float = 0.1;
    #if hl
    public static var ANALOG_BUTTON_THRESHOLDS = { press: 0.3, release: 0.25 };
    #end

    #if hlsdl
    public var d : sdl.Joystick;
    #end
    var rawXAxis : Float = 0.;
    var rawYAxis : Float = 0.;
    var rawRXAxis : Float = 0.;
    var rawRYAxis : Float = 0.;
    var prevButtons : Array<Bool> = [];

    static var sticks : Map<Int, Joystick> = new Map();
    static var waitPad : Joystick -> Void;
    static var initDone = false;

    function get_xAxis() {
        if( rawXAxis*rawXAxis + rawYAxis*rawYAxis < axisDeadZone*axisDeadZone ) return 0.;
        return rawXAxis;
    }

    function get_yAxis() {
        if( rawXAxis*rawXAxis + rawYAxis*rawYAxis < axisDeadZone*axisDeadZone ) return 0.;
        return rawYAxis;
    }

    function get_rxAxis() {
        if( rawRXAxis*rawRXAxis + rawRYAxis*rawRYAxis < axisDeadZone*axisDeadZone ) return 0.;
        return rawRXAxis;
    }

    function get_ryAxis() {
        if( rawRXAxis*rawRXAxis + rawRYAxis*rawRYAxis < axisDeadZone*axisDeadZone ) return 0.;
        return rawRYAxis;
    }

    function new() {
    }

    public function isDown( button : Int ) {
        return buttons[button];
    }

    public function isPressed( button : Int ) {
        return buttons[button] && !prevButtons[button];
    }

    public function isReleased( button : Int ) {
        return !buttons[button] && prevButtons[button];
    }

    public dynamic function onDisconnect(){
    }

    inline function _setAxis( axisId : Int, value : Int ){
        var v = value / 0x7FFF;

        _detectAnalogButton(axisId, v);

        // Invert Y axis
        if( axisId == 1 || axisId == 3 )
            values[ axisId ] = -v;
        else
            values[ axisId ] = v;

        if( axisId == 0 )
            rawXAxis = v;
        else if( axisId == 1 )
            rawYAxis = v;
        else if( axisId == 2 )
            rawRXAxis = v;
        else if( axisId == 3 )
            rawRYAxis = v;
    }

    #if hl
    inline function _setButton( btnId : Int, down : Bool ){
        buttons[ btnId ] = down;
        values[ btnId ] = down ? 1 : 0;
    }

    function _detectAnalogButton(index: Int, v: Float) {
        if(v > ANALOG_BUTTON_THRESHOLDS.press && v > values[index]) {
            buttons[ index ] = true;
        }
        if(v < ANALOG_BUTTON_THRESHOLDS.release && v < values[index]) {
            buttons[ index ] = false;
        }
    }
    #end

    static function initPad( index ){
        var sp = new sdl.Joystick( index );
        if( @:privateAccess sp.ptr == null )
            return;
        var j = new Joystick();
        j.index = sp.id;
        j.d = sp;
        var prev = sticks.get( j.index );
        if (prev != null) {
            sticks.remove( j.index );
            prev.d.close();
            prev.connected = false;
            prev.onDisconnect();
        }
        sticks.set( j.index, j );
        for( axis in 0...6 )
            j._setAxis( axis, sp.getAxis(axis) );
        for( button in 0...15 )
            j._setButton( button + 6, sp.getButton(button) );
        waitPad( j );
    }

    static function syncPads(){
        for( p in sticks ) {
            for( i in 0...p.buttons.length ) {
                p.prevButtons[i] = p.buttons[i];
                p._setButton( i, p.d.getButton(i) );
            }
            for( i in 0...p.values.length ) {
                p.prevValues[i] = p.values[i];
                p._setAxis( i, p.d.getAxis(i) );
            }
        }
    }

    public static function wait( onPad : Joystick -> Void ) {
        #if js
        if( !js.Browser.supported )
            return;
        #end
        waitPad = onPad;
        #if hlsdl
        if( !initDone ) {
            initDone = true;
            var c = @:privateAccess sdl.Joystick.joyCount();
            for( idx in 0...c )
                initPad( idx );
            haxe.MainLoop.add(syncPads);
        }
        #elseif (hldx || usesys)
        if( !initDone ){
            initDone = true;
            sdl.Joystick.init();
            haxe.MainLoop.add(syncPads);
        }
        #elseif js
        if( !initDone ) {
            initDone = true;
            js.Browser.window.addEventListener("gamepadconnected", function(p) {
                var pad = new hxd.Pad();
                pad.d = p.gamepad;
                pad.config = pickConfig(pad.d.id);
                pad.index = pad.d.index;
                pads.set(pad.d.index, pad);
                waitPad(pad);
            });
            js.Browser.window.addEventListener("gamepaddisconnected", function(p) {
                var pad = pads.get(p.gamepad.index);
                if( pad == null ) return;
                pads.remove(p.gamepad.index);
                pad.connected = false;
                pad.onDisconnect();
            });
            #if !manual_sync_pad
            haxe.MainLoop.add(syncPads);
            #end
        }
        #end
    }

}

@mufty
Copy link
Author

mufty commented Mar 7, 2024

The conclusion here is that it would need to be implemented in Heaps at least for Opengl for DirectX more research would be needed. Feel free to close this issue or plan accordingly whatever you feel like I'm just keeping this here for whoever might need it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants