diff --git a/.gitignore b/.gitignore
index 2a83b8307..0e9b29694 100644
--- a/.gitignore
+++ b/.gitignore
@@ -17,6 +17,7 @@ appimage/
*.cpp
*.vdf
.kateconfig
+*.kdev4
dist/
sccontroller.egg-info/
diff --git a/images/controller-images/deck.svg b/images/controller-images/deck.svg
index fdf7910e0..f00a586c4 100644
--- a/images/controller-images/deck.svg
+++ b/images/controller-images/deck.svg
@@ -7,7 +7,7 @@
viewBox="0 0 445.99999 345"
id="svg2"
version="1.1"
- inkscape:version="1.2 (dc2aedaf03, 2022-05-15)"
+ inkscape:version="1.2.2 (b0a8486541, 2022-12-01)"
sodipodi:docname="deck.svg"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
@@ -25,16 +25,16 @@
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
- inkscape:zoom="14.833317"
- inkscape:cx="213.33731"
- inkscape:cy="265.7868"
+ inkscape:zoom="7.4166584"
+ inkscape:cx="40.853978"
+ inkscape:cy="99.101234"
inkscape:document-units="px"
- inkscape:current-layer="controller"
+ inkscape:current-layer="layer2"
showgrid="false"
units="px"
- inkscape:window-width="1855"
- inkscape:window-height="1032"
- inkscape:window-x="65"
+ inkscape:window-width="1920"
+ inkscape:window-height="1005"
+ inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1"
fit-margin-top="0"
@@ -656,6 +656,74 @@
+
+
+
+
+
+
+
+
+
+ style="color:#000000;display:inline;overflow:visible;visibility:visible;opacity:1;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#ed00b4;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
+ inkscape:label="AREA_RSTICK_1" />
+ style="color:#000000;display:inline;overflow:visible;visibility:visible;opacity:1;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#ed00b4;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
+ inkscape:label="AREA_RSTICK_2" />
+ style="color:#000000;display:inline;overflow:visible;visibility:visible;opacity:1;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#ed00b4;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
+ inkscape:label="AREA_RSTICK_3" />
+ style="color:#000000;display:inline;overflow:visible;visibility:visible;opacity:1;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#ed00b4;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
+ inkscape:label="AREA_RSTICK_4" />
+ style="color:#000000;display:inline;overflow:visible;visibility:visible;opacity:1;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#ed00b4;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
+ inkscape:label="AREA_RSTICK_5" />
+ style="color:#000000;display:inline;overflow:visible;visibility:visible;opacity:1;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#ed00b4;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;enable-background:accumulate"
+ inkscape:label="AREA_RSTICK_6" />
+ ry="0"
+ inkscape:label="AREA_RSTICKTEST" />
+
diff --git a/scc/drivers/steamdeck.py b/scc/drivers/steamdeck.py
index 84f94c589..2d381bf41 100644
--- a/scc/drivers/steamdeck.py
+++ b/scc/drivers/steamdeck.py
@@ -192,9 +192,8 @@ def _on_input(self, endpoint, data):
self.daemon.add_controller(self)
self.configure()
self._ready = True
-
- # Don't like this version
- #self._old_state, self._input = self._input, self._old_state
+
+ self._old_state, self._input = self._input, self._old_state
ctypes.memmove(ctypes.addressof(self._input), data, len(data))
if self._input.seq % UNLIZARD_INTERVAL == 0:
# Keeps lizard mode from happening
@@ -222,16 +221,13 @@ def _on_input(self, endpoint, data):
self._input.stick_y = apply_deadzone(self._input.stick_y, STICK_DEADZONE)
self._input.rstick_x = apply_deadzone(self._input.rstick_x, STICK_DEADZONE)
self._input.rstick_y = apply_deadzone(self._input.rstick_y, STICK_DEADZONE)
-
+
# Invert Gyro Roll to match Steam Controller coordinate system
self._input.groll = -self._input.groll
-
+
m = self.get_mapper()
if m:
self.mapper.input(self, self._old_state, self._input)
-
- # Preserve current state into previous state object
- self._old_state = self._input
def close(self):
if self._ready:
diff --git a/scc/gui/app.py b/scc/gui/app.py
index 99b70b995..900f536c4 100644
--- a/scc/gui/app.py
+++ b/scc/gui/app.py
@@ -20,7 +20,7 @@
from scc.gui.ribar import RIBar
from scc.tools import check_access, find_gksudo, profile_is_override, nameof
from scc.tools import get_profile_name, profile_is_default, find_profile
-from scc.constants import SCButtons, STICK, STICK_PAD_MAX
+from scc.constants import SCButtons, STICK, RSTICK, STICK_PAD_MAX
from scc.constants import DAEMON_VERSION, LEFT, RIGHT
from scc.paths import get_config_path, get_profiles_path
from scc.custom import load_custom_module
@@ -135,10 +135,14 @@ def setup_widgets(self):
self.lpad_test = Gtk.Image.new_from_file(os.path.join(self.imagepath, "test-cursor.svg"))
self.rpad_test = Gtk.Image.new_from_file(os.path.join(self.imagepath, "test-cursor.svg"))
self.stick_test = Gtk.Image.new_from_file(os.path.join(self.imagepath, "test-cursor.svg"))
+ self.rstick_test = Gtk.Image.new_from_file(os.path.join(self.imagepath, "test-cursor.svg"))
+ self.dpad_test = Gtk.Image.new_from_file(os.path.join(self.imagepath, "test-cursor.svg"))
self.main_area.put(self.lpad_test, 40, 40)
self.main_area.put(self.rpad_test, 290, 90)
self.main_area.put(self.stick_test, 150, 40)
-
+ self.main_area.put(self.rstick_test, 290, 40)
+ self.main_area.put(self.dpad_test, 38, 78)
+
# OSD mode (if used)
if self.osd_mode:
self.builder.get_object("btDaemon").set_sensitive(False)
@@ -992,16 +996,16 @@ def enable_test_mode(self):
if self.test_mode_controller:
self.test_mode_controller.unlock_all()
try:
- c = self.dm.get_controllers()[0]
+ c = self.profile_switchers[0].get_controller()
except IndexError:
# Zero controllers
return
if c:
c.unlock_all()
c.observe(DaemonManager.nocallback, self.on_observe_failed,
- 'A', 'B', 'C', 'X', 'Y', 'START', 'BACK', 'LB', 'RB',
- 'LPAD', 'RPAD', 'LGRIP', 'RGRIP', 'LT', 'RT', 'LEFT',
- 'RIGHT', 'STICK', 'STICKPRESS')
+ 'A', 'B', 'C', 'X', 'Y', 'START', 'BACK', 'DOTS', 'LB', 'RB',
+ 'LPAD', 'RPAD', 'LGRIP', 'LGRIP2', 'RGRIP', 'RGRIP2', 'LT', 'RT', 'LEFT',
+ 'RIGHT', 'STICK', 'STICKPRESS', 'RSTICK', 'RSTICKPRESS', 'DPAD')
self.test_mode_controller = c
@@ -1108,11 +1112,12 @@ def on_daemon_error(self, daemon, error):
def on_daemon_event_observer(self, daemon, c, what, data):
if self.osd_mode_mapper:
self.osd_mode_mapper.handle_event(daemon, what, data)
- elif what in (LEFT, RIGHT, STICK):
+ elif what in (LEFT, RIGHT, STICK, RSTICK):
widget, area = {
LEFT : (self.lpad_test, "LPADTEST"),
RIGHT : (self.rpad_test, "RPADTEST"),
STICK : (self.stick_test, "STICKTEST"),
+ RSTICK : (self.rstick_test, "RSTICKTEST"),
}[what]
# Check if stick or pad is released
if data[0] == data[1] == 0:
@@ -1130,12 +1135,36 @@ def on_daemon_event_observer(self, daemon, c, what, data):
y -= data[1] * aw / STICK_PAD_MAX * 0.5
# Move circle
self.main_area.move(widget, x, y)
- elif what in ("LT", "RT", "STICKPRESS"):
+ elif what in ("LT", "RT", "STICKPRESS", "RSTICKPRESS"):
if data[0]:
self.hilights[App.OBSERVE_COLOR].add(what)
else:
self.hilights[App.OBSERVE_COLOR].remove(what)
self._update_background()
+ elif what == "DPAD":
+ if data[0] == 0 and data[1] == 0:
+ self.dpad_test.hide()
+ else:
+ ax, ay, aw, ah = self.background.get_area_position("DPADTEST")
+ cw = self.dpad_test.get_allocation().width
+ ch = self.dpad_test.get_allocation().height
+
+ pos_left = [ax , ay + ah/2 - ch/2]
+ pos_right = [ax + aw - cw , ay + ah/2 - ch/2]
+ pos_top = [ax + aw/2 - cw/2, ay]
+ pos_bottom = [ax + aw/2 - cw/2, ay + ah - ch]
+
+ if data[0] < 0:
+ pos = pos_left
+ elif data[0] > 0:
+ pos = pos_right
+ elif data[1] < 0:
+ pos = pos_bottom
+ elif data[1] > 0:
+ pos = pos_top
+
+ self.main_area.move(self.dpad_test, pos[0], pos[1])
+ self.dpad_test.show()
elif hasattr(SCButtons, what):
try:
if data[0]:
diff --git a/scc/gui/controller_image.py b/scc/gui/controller_image.py
index 7c6f3578a..849ffcbfa 100644
--- a/scc/gui/controller_image.py
+++ b/scc/gui/controller_image.py
@@ -157,6 +157,8 @@ def _fill_button_images(self, buttons):
for i in range(len(ControllerImage.BUTTONS_WITH_IMAGES)):
b = nameof(ControllerImage.BUTTONS_WITH_IMAGES[i])
if b == "DOTS":
+ if self.current["gui"]["background"] != "deck":
+ continue
# How did I managed to create this kind of special case? -_-
i = 16
path = None
diff --git a/scc/gui/daemon_manager.py b/scc/gui/daemon_manager.py
index d68c67c6a..f2f8d7b2b 100644
--- a/scc/gui/daemon_manager.py
+++ b/scc/gui/daemon_manager.py
@@ -348,7 +348,7 @@ class ControllerManager(GObject.GObject):
}
DEFAULT_ICONS = [ "A", "B", "X", "Y", "BACK", "C", "START",
- "LB", "RB", "LT", "RT", "STICK", "LPAD", "RPAD", "RGRIP", "LGRIP", "DOTS" ]
+ "LB", "RB", "LT", "RT", "STICK", "RSTICK", "LPAD", "RPAD", "RGRIP", "LGRIP", "DOTS" ]
# ^^ those are icon names
def __init__(self, daemon_manager, controller_id, controller_type):
diff --git a/scc/gui/statusicon.py b/scc/gui/statusicon.py
index 836004927..5f6405dd5 100644
--- a/scc/gui/statusicon.py
+++ b/scc/gui/statusicon.py
@@ -263,6 +263,8 @@ def __init__(self, *args, **kwargs):
StatusIcon.__init__(self, *args, **kwargs)
try:
+ import gi
+ gi.require_version('AppIndicator3', '0.1')
from gi.repository import AppIndicator3 as appindicator
self._status_active = appindicator.IndicatorStatus.ACTIVE
@@ -350,8 +352,8 @@ def _load_fallback(self):
for StatusIconBackend in status_icon_backends:
try:
self._status_fb = StatusIconBackend(*self._arguments[0], **self._arguments[1])
- self._status_fb.connect(b"clicked", self._on_click)
- self._status_fb.connect(b"notify::active", self._on_notify_active_fb)
+ self._status_fb.connect("clicked", self._on_click)
+ self._status_fb.connect("notify::active", self._on_notify_active_fb)
self._on_notify_active_fb()
log.warning("StatusIcon: Using backend %s (fallback)" % StatusIconBackend.__name__)
diff --git a/scc/gui/svg_widget.py b/scc/gui/svg_widget.py
index 7cfdd32d0..b66ab2d62 100644
--- a/scc/gui/svg_widget.py
+++ b/scc/gui/svg_widget.py
@@ -49,6 +49,7 @@ def __init__(self, filename, init_hilighted=True):
self.size_override = None
self.image_width = 1
self.image_height = 1
+ self.filename = filename
self.set_image(filename)
self.image = Gtk.Image()
if init_hilighted:
@@ -58,6 +59,7 @@ def __init__(self, filename, init_hilighted=True):
def set_image(self, filename):
+ self.filename = filename
self.current_svg = open(filename, "r").read()
self.cache = OrderedDict()
self.areas = []
@@ -139,7 +141,7 @@ def get_area_position(self, area_id):
a = self.get_area(area_id)
if a:
return a.x, a.y, a.w, a.h
- raise ValueError("Area '%s' not found" % (area_id, ))
+ raise ValueError("Area '%s' not found in '%s'" % (area_id, self.filename))
@staticmethod
diff --git a/scc/osd/inputdisplay.py b/scc/osd/inputdisplay.py
index eb9ab1e14..ba8b19ddd 100644
--- a/scc/osd/inputdisplay.py
+++ b/scc/osd/inputdisplay.py
@@ -6,7 +6,7 @@
from scc.tools import _, set_logging_level
from gi.repository import Gtk, GLib
-from scc.constants import SCButtons, STICK, LEFT, RIGHT, STICK_PAD_MAX
+from scc.constants import SCButtons, STICK, RSTICK, LEFT, RIGHT, STICK_PAD_MAX
from scc.gui.daemon_manager import DaemonManager
from scc.gui.svg_widget import SVGWidget
from scc.osd import OSDWindow
@@ -36,7 +36,8 @@ def show(self):
self.lpadTest = Gtk.Image.new_from_file(os.path.join(self.imagepath, "inputdisplay-cursor.svg"))
self.rpadTest = Gtk.Image.new_from_file(os.path.join(self.imagepath, "inputdisplay-cursor.svg"))
self.stickTest = Gtk.Image.new_from_file(os.path.join(self.imagepath, "inputdisplay-cursor.svg"))
-
+ self.rStickTest = Gtk.Image.new_from_file(os.path.join(self.imagepath, "inputdisplay-cursor.svg"))
+
self.main_area.set_property("margin-left", 10)
self.main_area.set_property("margin-right", 10)
self.main_area.set_property("margin-top", 10)
@@ -46,14 +47,15 @@ def show(self):
self.main_area.put(self.lpadTest, 40, 40)
self.main_area.put(self.rpadTest, 290, 90)
self.main_area.put(self.stickTest, 150, 40)
-
+ self.main_area.put(self.rStickTest, 290, 40)
+
self.add(self.main_area)
OSDWindow.show(self)
self.lpadTest.hide()
self.rpadTest.hide()
self.stickTest.hide()
-
+ self.rStickTest.hide()
def run(self):
self.daemon = DaemonManager()
@@ -85,7 +87,7 @@ def on_daemon_connected(self, *a):
c.observe(DaemonManager.nocallback, self.on_observe_failed,
'A', 'B', 'C', 'X', 'Y', 'START', 'BACK', 'LB', 'RB',
'LPAD', 'RPAD', 'LGRIP', 'RGRIP', 'LT', 'RT', 'LEFT',
- 'RIGHT', 'STICK', 'STICKPRESS')
+ 'RIGHT', 'STICK', 'STICKPRESS', 'RSTICK', 'RSTICKPRESS')
c.connect('event', self.on_daemon_event_observer)
c.connect('lost', self.on_controller_lost)
@@ -101,11 +103,12 @@ def on_observe_failed(self, error):
def on_daemon_event_observer(self, daemon, what, data):
- if what in (LEFT, RIGHT, STICK):
+ if what in (LEFT, RIGHT, STICK, RSTICK):
widget, area = {
- LEFT : (self.lpadTest, "LPADTEST"),
- RIGHT : (self.rpadTest, "RPADTEST"),
- STICK : (self.stickTest, "STICKTEST"),
+ LEFT : (self.lpadTest, "LPADTEST"),
+ RIGHT : (self.rpadTest, "RPADTEST"),
+ STICK : (self.stickTest, "STICKTEST"),
+ RSTICK : (self.rStickTest, "RSTICKTEST"),
}[what]
# Check if stick or pad is released
if data[0] == data[1] == 0:
@@ -123,11 +126,12 @@ def on_daemon_event_observer(self, daemon, what, data):
y -= data[1] * aw / STICK_PAD_MAX * 0.5
# Move circle
self.main_area.move(widget, x, y)
- elif what in ("LT", "RT", "STICKPRESS"):
+ elif what in ("LT", "RT", "STICKPRESS", "RSTICKPRESS"):
what = {
"LT" : "LEFT",
"RT" : "RIGHT",
- "STICKPRESS" : "STICK"
+ "STICKPRESS" : "STICK",
+ "RSTICKPRESS" : "RSTICK"
}[what]
if data[0]:
self.hilights[self.OBSERVE_COLOR].add(what)
diff --git a/scc/sccdaemon.py b/scc/sccdaemon.py
index 4ef65a3f5..13df87eb4 100644
--- a/scc/sccdaemon.py
+++ b/scc/sccdaemon.py
@@ -1099,11 +1099,14 @@ def source_to_constant(s):
Used when parsing `Lock: ...` message
"""
s = s.decode("utf-8").strip(" \t\r\n")
- if s in (STICK, LEFT, RIGHT, CPAD):
+ if s in (STICK, RSTICK, LEFT, RIGHT, CPAD, DPAD):
return s
if s == "STICKPRESS":
# Special case, as that button is actually named STICK :(
return SCButtons.STICKPRESS
+ if s == "RSTICKPRESS":
+ # Special case, as that button is actually named STICK :(
+ return SCButtons.RSTICKPRESS
if hasattr(SCButtons, s):
return getattr(SCButtons, s)
raise ValueError("Unknown source: %s" % (s,))