Steam Deck input (SOLVED)

I think I’d send the user a test app with Raw gamepad input and show all of the buttons. Like this:

From that you can create your own .gamepad binding entry. I did this to get gamepad bindings for iiRcade when releasing Trigger Dungeon on their platform. I don’t think I have that test app left (stupid, yeah, I know).

2 Likes

That seems a sensible approach, shame your app is dead :sweat_smile:

How do I get this info? If I pprint the raw action I just get things like:

{ --[[000001A85D444530]]
  pressed = false,
  released = false,
  repeated = false,
  dx = 0,
  dy = 0,
  screen_x = 474,
  screen_y = 134,
  screen_dx = 0,
  screen_dy = 0,
  y = 133.5,
  x = 474.5,
  gamepad = 0,
  value = 0
}

There should be one subtable for each input type: buttons, axis, hats.

Connect a gamepad of your own, map a raw binding and check the action table!

Hmm, but the above was a pprint of the action table for the raw input of my Xbox 360 controller?

That is strange. And the action_id was matching what you have in your input bindings for the Raw gamepad event?

Sorry for the delay. Yes:

function on_input(self, action_id, action)
	
	if action_id == hash("gamepad_raw") then
        pprint(action)
	end
end

image

DEBUG:SCRIPT: 
{ --[[00000207A88F7E60]]
  y = 628.5,
  dx = 0,
  x = 898.5,
  dy = 0,
  gamepad = 0,
  value = 0,
  pressed = false,
  released = false,
  repeated = false,
  screen_x = 898,
  screen_y = 629,
  screen_dx = 0,
  screen_dy = 0
}

Searching the entirety of the debug output doesn’t return “hats” for example.

Here’s the project:
Steamdeck_utility.zip (1.6 MB)

Have you tested this both locally on a computer with a connected gamepad and on the steam deck?

My last post is about me on my Windows machine with an old Xbox 360 controller.

Re: the Steam Deck, I know raw input is detected, but I haven’t gotten as far as trying to detect hats/axis etc.

I can’t really explain it then. The raw input should be cross platform. Please open a ticket on GH so that we can investigate further.

1 Like

Posted issue here:

I am launching a game on Steam soon and would love to have Steam Deck working, but I suspect it’s unlikely the issue will be resolved by then.

The first step is to make sure I haven’t messed something up in my repro. Can someone with a gamepad check if they are able to get detailed data for raw gamepad input (i.e. buttons, axis, hats)?

Perhaps, yes. I’m going to look into the raw gamepad issue next week though.

1 Like

Also, we’ve ordered a Steam Deck back in April and it is supposed to be delivered sometime in Oct-Dec…

1 Like

Great!

Mine is on the way! So if we resolve the raw gamepad issue then I can do some testing myself.

2 Likes

I finally have a Steam Deck!

The issue with raw gamepad input was that gui scripts don’t receive it, but regular scripts do. Armed with this knowledge, I recreated a utility similar to what @britzl mentioned. This is me partially mapping my old Xbox controller:

Regrettably, I just don’t seem to get any input from the Steam Deck - other than an unexpected gamepad name:

For reference, this is the script I use to gather mappings. Might be useful for other situations:


--pre-hash
local GAMEPAD_LSTICK_LEFT = hash("gamepad_lstick_left")
local GAMEPAD_LSTICK_RIGHT = hash("gamepad_lstick_right")
local GAMEPAD_LSTICK_DOWN = hash("gamepad_lstick_down")
local GAMEPAD_LSTICK_UP = hash("gamepad_lstick_up")
local GAMEPAD_LSTICK_CLICK = hash("gamepad_lstick_click")
local GAMEPAD_LTRIGGER = hash("gamepad_ltrigger")
local GAMEPAD_LSHOULDER = hash("gamepad_lshoulder")
local GAMEPAD_LPAD_LEFT = hash("gamepad_lpad_left")
local GAMEPAD_LPAD_RIGHT = hash("gamepad_lpad_right")
local GAMEPAD_LPAD_DOWN = hash("gamepad_lpad_down")
local GAMEPAD_LPAD_UP = hash("gamepad_lpad_up")
local GAMEPAD_RSTICK_LEFT = hash("gamepad_rstick_left")
local GAMEPAD_RSTICK_RIGHT = hash("gamepad_rstick_right")
local GAMEPAD_RSTICK_DOWN = hash("gamepad_rstick_down")
local GAMEPAD_RSTICK_UP = hash("gamepad_rstick_up")
local GAMEPAD_RSTICK_CLICK = hash("gamepad_rstick_click")
local GAMEPAD_RTRIGGER = hash("gamepad_rtrigger")
local GAMEPAD_RSHOULDER = hash("gamepad_rshoulder")
local GAMEPAD_RPAD_LEFT = hash("gamepad_rpad_left")
local GAMEPAD_RPAD_RIGHT = hash("gamepad_rpad_right")
local GAMEPAD_RPAD_DOWN = hash("gamepad_rpad_down")
local GAMEPAD_RPAD_UP = hash("gamepad_rpad_up")
local GAMEPAD_START = hash("gamepad_start")
local GAMEPAD_BACK = hash("gamepad_back")
local GAMEPAD_GUIDE = hash("gamepad_guide")

local hash_to_text = {
	[GAMEPAD_LSTICK_LEFT] = "GAMEPAD_LSTICK_LEFT",
	[GAMEPAD_LSTICK_RIGHT] = "GAMEPAD_LSTICK_RIGHT",
	[GAMEPAD_LSTICK_DOWN] = "GAMEPAD_LSTICK_DOWN",
	[GAMEPAD_LSTICK_UP] = "GAMEPAD_LSTICK_UP",
	[GAMEPAD_LSTICK_CLICK] = "GAMEPAD_LSTICK_CLICK",
	[GAMEPAD_LTRIGGER] = "GAMEPAD_LTRIGGER",
	[GAMEPAD_LSHOULDER] = "GAMEPAD_LSHOULDER",
	[GAMEPAD_LPAD_LEFT] = "GAMEPAD_LPAD_LEFT",
	[GAMEPAD_LPAD_RIGHT] = "GAMEPAD_LPAD_RIGHT",
	[GAMEPAD_LPAD_DOWN] = "GAMEPAD_LPAD_DOWN",
	[GAMEPAD_LPAD_UP] = "GAMEPAD_LPAD_UP",
	[GAMEPAD_RSTICK_LEFT] = "GAMEPAD_RSTICK_LEFT",
	[GAMEPAD_RSTICK_RIGHT] = "GAMEPAD_RSTICK_RIGHT",
	[GAMEPAD_RSTICK_DOWN] = "GAMEPAD_RSTICK_DOWN",
	[GAMEPAD_RSTICK_UP] = "GAMEPAD_RSTICK_UP",
	[GAMEPAD_RSTICK_CLICK] = "GAMEPAD_RSTICK_CLICK",
	[GAMEPAD_RTRIGGER] = "GAMEPAD_RTRIGGER",
	[GAMEPAD_RSHOULDER] = "GAMEPAD_RSHOULDER",
	[GAMEPAD_RPAD_LEFT] = "GAMEPAD_RPAD_LEFT",
	[GAMEPAD_RPAD_RIGHT] = "GAMEPAD_RPAD_RIGHT",
	[GAMEPAD_RPAD_DOWN] = "GAMEPAD_RPAD_DOWN",
	[GAMEPAD_RPAD_UP] = "GAMEPAD_RPAD_UP",
	[GAMEPAD_START] = "GAMEPAD_START",
	[GAMEPAD_BACK] = "GAMEPAD_BACK",
	[GAMEPAD_GUIDE] = "GAMEPAD_GUIDE",
}

function init(self)
	msg.post(".", "acquire_input_focus")

	self.data = {}
	self.formatted_data = {}
end

function update(self, dt)
	
	if self.gamepad_name then
		label.set_text("#gamepad_name", "Gamepad name: " .. self.gamepad_name)
	else
		label.set_text("#gamepad_name", "No gamepad detected.")
	end

	local txt = ""
	for name, data in pairs(self.data) do
		
		txt = txt .. name .. " type: " .. data.type .. " index: " .. data.index .. "\n"
	end
	label.set_text("#mapping", txt)

	self.formatted_data = {}
	for name, data in pairs(self.data) do
		if data.type == "GAMEPAD_TYPE_HAT" then
			table.insert(self.formatted_data, "map { input: " .. name .. " type: " .. data.type .. " index: 0 hat_mask: " .. data.index .. " }")
		elseif data.type == "GAMEPAD_TYPE_AXIS" then
			--this needs "mod" details, do manually
			table.insert(self.formatted_data, "map { input: " .. name .. " type: " .. data.type .. " index: " .. data.index .. " }")
		else
			table.insert(self.formatted_data, "map { input: " .. name .. " type: " .. data.type .. " index: " .. data.index .. " }")
		end
	end
	pprint(self.formatted_data)
end

function on_input(self, action_id, action)
	
	if action_id == hash("gamepad_connected") then
		self.gamepad_name = action.gamepad_name
	end

	if action_id == hash("gamepad_raw") then
		self.previous_raw = action
	else
		if action.pressed then

			if not self.previous_raw then
				return
			end

			--is it a button?
			for i, state in pairs(self.previous_raw.gamepad_buttons) do
				if state == 1 then
					self.data[hash_to_text[action_id]] = {type = "GAMEPAD_TYPE_BUTTON", index = i}
					break
				end
			end

			--is it an axis?
			local largest_state = 0
			local largest_i = nil
			for i, state in pairs(self.previous_raw.gamepad_axis) do
				state = math.abs(state)
				if state > 0.5 then
					if state > largest_state then
						largest_state = state
						largest_i = i
					end
				end
			end
			if largest_i then
				self.data[hash_to_text[action_id]] = {type = "GAMEPAD_TYPE_AXIS", index = largest_i}
			end

			--is it a hat?
			for i, state in pairs(self.previous_raw.gamepad_hats) do
				if state == 1 then
					self.data[hash_to_text[action_id]] = {type = "GAMEPAD_TYPE_HAT", index = i}
					break
				end
			end
		end
	end
end

I think the axis detection needs some work because I use math.abs() when I actually think there are supposed to be negative values.

I’m at a loss as to how to move forward at this point!

2 Likes

Yep, that’s an oversight on our part. I’ll see about fixing that soon!

Ok, but you do get a gamepad connected event and that name?

I think next step would be to prepare a version of Defold with some additional to try and pinpoint where it goes wrong with joystick/gamepad detection.

1 Like

Yes, I do get a gamepad_connected event with that name.

What additional things would you try?

I don’t know really. We use Xinput on Linux, but it could be that we need to look more closely at the implementation and how the Steam Deck works.

1 Like

OK. Perhaps something to look at when you get your Deck. I’ve managed to get Void Scrappers to work by emulating mouse + keyboard, so for me personally it’s just Fates of Ort that doesn’t work.

1 Like

Ok, so I was a dummy! My script would only ever catch mapped input so no surprise it wasn’t displaying anything.

I’ve fixed that now and actually got some input! I mapped it and tried again.

The keys in my mapping don’t match up at all, it seems. I thought that perhaps the generic sounding name (“Microsoft X-Box 360 pad 0”) might be clashing with other similarly named mappings, so I tried a build with just mine. Still doesn’t match. Why might that be?!

Here's my mapping
driver
{
    device: "Microsoft X-Box 360 pad 0"
    platform: "linux"
    dead_zone: 0.2
    map { input: GAMEPAD_LSTICK_LEFT type: GAMEPAD_TYPE_AXIS index: 1 mod { mod: GAMEPAD_MODIFIER_NEGATE } mod { mod: GAMEPAD_MODIFIER_CLAMP } }
    map { input: GAMEPAD_LSTICK_RIGHT type: GAMEPAD_TYPE_AXIS index: 1 mod { mod: GAMEPAD_MODIFIER_CLAMP } }
    map { input: GAMEPAD_LSTICK_DOWN type: GAMEPAD_TYPE_AXIS index: 2 mod { mod: GAMEPAD_MODIFIER_NEGATE } mod { mod: GAMEPAD_MODIFIER_CLAMP } }
    map { input: GAMEPAD_LSTICK_UP type: GAMEPAD_TYPE_AXIS index: 2 mod { mod: GAMEPAD_MODIFIER_CLAMP } }
    map { input: GAMEPAD_LSTICK_CLICK type: GAMEPAD_TYPE_BUTTON index: 10 }
    map { input: GAMEPAD_LTRIGGER type: GAMEPAD_TYPE_AXIS index: 3 mod { mod: GAMEPAD_MODIFIER_SCALE } }
    map { input: GAMEPAD_LSHOULDER type: GAMEPAD_TYPE_BUTTON index: 5 }
    map { input: GAMEPAD_LPAD_LEFT type: GAMEPAD_TYPE_AXIS index: 7 mod { mod: GAMEPAD_MODIFIER_NEGATE } mod { mod: GAMEPAD_MODIFIER_CLAMP } }
    map { input: GAMEPAD_LPAD_RIGHT type: GAMEPAD_TYPE_AXIS index: 7 mod { mod: GAMEPAD_MODIFIER_CLAMP } }
    map { input: GAMEPAD_LPAD_DOWN type: GAMEPAD_TYPE_AXIS index: 8 mod { mod: GAMEPAD_MODIFIER_NEGATE } mod { mod: GAMEPAD_MODIFIER_CLAMP } }
    map { input: GAMEPAD_LPAD_UP type: GAMEPAD_TYPE_AXIS index: 8 mod { mod: GAMEPAD_MODIFIER_CLAMP } }
    map { input: GAMEPAD_RSTICK_LEFT type: GAMEPAD_TYPE_AXIS index: 4 mod { mod: GAMEPAD_MODIFIER_CLAMP } }
    map { input: GAMEPAD_RSTICK_RIGHT type: GAMEPAD_TYPE_AXIS index: 4 mod { mod: GAMEPAD_MODIFIER_NEGATE } mod { mod: GAMEPAD_MODIFIER_CLAMP } }
    map { input: GAMEPAD_RSTICK_DOWN type: GAMEPAD_TYPE_AXIS index: 5 mod { mod: GAMEPAD_MODIFIER_CLAMP } }
    map { input: GAMEPAD_RSTICK_UP type: GAMEPAD_TYPE_AXIS index: 5 mod { mod: GAMEPAD_MODIFIER_NEGATE } mod { mod: GAMEPAD_MODIFIER_CLAMP } }
    map { input: GAMEPAD_RSTICK_CLICK type: GAMEPAD_TYPE_BUTTON index: 11 }
    map { input: GAMEPAD_RTRIGGER type: GAMEPAD_TYPE_AXIS index: 6 mod { mod: GAMEPAD_MODIFIER_NEGATE } mod { mod: GAMEPAD_MODIFIER_SCALE } }
    map { input: GAMEPAD_RSHOULDER type: GAMEPAD_TYPE_BUTTON index: 6 }
    map { input: GAMEPAD_RPAD_LEFT type: GAMEPAD_TYPE_BUTTON index: 3 }
    map { input: GAMEPAD_RPAD_RIGHT type: GAMEPAD_TYPE_BUTTON index: 2 }
    map { input: GAMEPAD_RPAD_DOWN type: GAMEPAD_TYPE_BUTTON index: 1 }
    map { input: GAMEPAD_RPAD_UP type: GAMEPAD_TYPE_BUTTON index: 4 }
    map { input: GAMEPAD_START type: GAMEPAD_TYPE_BUTTON index: 8 }
    map { input: GAMEPAD_BACK type: GAMEPAD_TYPE_BUTTON index: 7 }
}
1 Like