kozec / sc-controller

User-mode driver and GTK3 based GUI for Steam Controller
GNU General Public License v2.0
1.53k stars 129 forks source link

Option for circular scrolling? #29

Closed parkerlreed closed 8 years ago

parkerlreed commented 8 years ago

Aka Steam's scrolling method.

kozec commented 8 years ago

It's in TODO, but it kinda belongs to list of things I have no idea how to do mathematically :(

z33ky commented 8 years ago

I'm guessing you can get the x and y values of the pad. You need to get them in a range [-l,l] (where l is some arbitrary number > 0, e.g. 1) and then use atan2(y, x) to get an angle, which is the angle between a line in the middle of the pad going horizontally and the line going from the middle to the position of the finger.

Store that angle and subtract from it the angle you get on the next update to see if you were moving clockwise (result is positive) or counter-clockwise (negative) (assuming that the x and y values increase when going up and right). Some care needs to be taken when wrapping around from -pi to pi (that is -180° to 180°) or vice versa, I'd check if the difference is > pi and if so just toggle the sign of the difference calculated.

You might also want to check that the finger isn't too close to the center.

I might give it a stab myself on the weekend should this still be open, though I'm not familiar with the code.

z33ky commented 8 years ago

I have a proof of concept implementation, however I don't think the code is in the right place. And it's hard-coded - but it does work. I hope this helps.

--- a/scc/mapper.py
+++ b/scc/mapper.py
@@ -2,6 +2,7 @@
 from __future__ import unicode_literals

 from collections import deque
+from math import atan2, pi
 from scc.uinput import Gamepad, Keyboard, Mouse, Rels
 from scc.constants import SCStatus, SCButtons, SCI_NULL
 from scc.constants import FE_STICK, FE_TRIGGER, FE_PAD
@@ -105,6 +106,7 @@ class Mapper(object):
        """ Used by trackpad, trackball and mouse wheel emulation """
        for axis in axes:
            self.mouse_dq[axis].clear()
+       self.angle = None

    def mouse_dq_add(self, axis, position, speed, hapticdata):
@@ -261,7 +263,14 @@ class Mapper(object):
            self.syn_list.add(self.mouse)
            self.mouse_movements[0] = self.mouse_movements[1] = None
        if wx != 0 or wy != 0:
-           if self.mouse.scrollEvent(wx, wy, False):
+           angle = atan2(self.mouse_dq[2][-1], self.mouse_dq[3][-1])
+           if self.angle is None:
+               self.angle, angle = angle, 0
+           else:
+               self.angle, angle = angle, self.angle - angle
+               if abs(angle) > pi:
+                   angle = -angle
+           if self.mouse.scrollEvent(0, angle * 8000, False):
                # Returns True
                self.travelled[1] += 500
            self.syn_list.add(self.mouse)

self.angle stores the previous angle. If it is None then we just placed the finger on the pad.

kozec commented 8 years ago

Great, thanks. I'm working on deadzones right now, but this is number two in today plan :)

kozec commented 8 years ago

Yep, it works :)

z33ky commented 8 years ago

The wrapping condition is actually wrong, it flips out a bit when you place the finger near the bottom.

                # Ensure we don't wrap from pi to -pi creating a large delta
                if angle > pi:
                    # Subtract a full rotation to counter the wrapping
                    angle -= 2 * pi
                # And same from -pi to pi
                elif angle < -pi:
                    # Add a full rotation to counter the wrapping
                    angle += 2 * pi

That instead of the if abs(angle) > pi: angle -= pi fixes that.

And the scroll event code can also be moved inside the else-branch, since when angle is 0 not much scrolling will happen.

kozec commented 8 years ago

I'm not sure about that last one. if abs(angle) > pi: angle -= pi looks working, but this new one scrolls up - down - up - down while I'm moving finger only clock-wise.

z33ky commented 8 years ago

I get the same problem with the current version, too :S

The x and y are relative movements not absolute coordinates, right? They're supposed to be the latter.

kozec commented 8 years ago

The x and y are relative movements not absolute coordinates, right? They're supposed to be the latter.

Absolute coordinates from -0x8000 to 0x8000 with (0,0) in center of pad.

Which one is current version right now?

z33ky commented 8 years ago

Argh, I forgot to click 'OK', I just closed the configuration window so it was still on the non-circular scrolling :(

Anyway, I'm on commit ca85ea000680ecc10460d4922dc676d7ad5ab7cc. Without modification I do get the jittery scrolling when I place my finger near the bottom, just very slightly to the left. With the change I proposed to handle the wrapping it works fine, also scrolling without alternating directions when continuing to draw circles.

kozec commented 8 years ago

I'm not 100% sure if mine does the same, but does this branch works as expected?

z33ky commented 8 years ago

That works. No jittering and no unexpected change in direction.

kozec commented 8 years ago

Great :)

Merged as 6df2085ecac5e15d5102b00e55428d4b5ff7fe2b

parkerlreed commented 8 years ago

Working great! Thanks.