Hello community,

here is the log from the commit of package sc-controller for openSUSE:Factory 
checked in at 2019-07-12 11:59:48
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/sc-controller (Old)
 and      /work/SRC/openSUSE:Factory/.sc-controller.new.4615 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "sc-controller"

Fri Jul 12 11:59:48 2019 rev:4 rq:714459 version:0.4.7

Changes:
--------
--- /work/SRC/openSUSE:Factory/sc-controller/sc-controller.changes      
2018-12-31 09:47:38.466154937 +0100
+++ /work/SRC/openSUSE:Factory/.sc-controller.new.4615/sc-controller.changes    
2019-07-12 11:59:49.580171928 +0200
@@ -1,0 +2,11 @@
+Tue Jul  9 11:34:41 UTC 2019 - Jannik Seiler <[email protected]>
+
+- Update to version 0.4.7
+  * Added option to send gyroscope data to Citra and Cemu (Cemuhook support)
+  * Fixes in 0.4.7:
+  * Not minimizing to tray on start
+  * Issues when using stick simultaneously with lpad
+  * Crash in controller registration dialog if udev device has special symbols 
in name (thanks @Verequies)
+  * Trackball friction resets when set to zero
+
+-------------------------------------------------------------------

Old:
----
  sc-controller-0.4.6.1.tar.gz

New:
----
  sc-controller-0.4.7.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ sc-controller.spec ++++++
--- /var/tmp/diff_new_pack.Yw7CSb/_old  2019-07-12 11:59:51.408171983 +0200
+++ /var/tmp/diff_new_pack.Yw7CSb/_new  2019-07-12 11:59:51.408171983 +0200
@@ -17,7 +17,7 @@
 
 
 Name:           sc-controller
-Version:        0.4.6.1
+Version:        0.4.7
 Release:        0
 Summary:        User-mode driver and GTK3-based GUI for the Steam Controller
 License:        GPL-2.0-only
@@ -30,6 +30,7 @@
 BuildRequires:  hicolor-icon-theme
 BuildRequires:  pkgconfig
 BuildRequires:  shared-mime-info
+BuildRequires:  zlib-devel
 BuildRequires:  pkgconfig(python2)
 BuildRequires:  pkgconfig(udev)
 #Requires:       libgtk-3-0

++++++ sc-controller-0.4.6.1.tar.gz -> sc-controller-0.4.7.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/sc-controller-0.4.6.1/appimage-build.sh 
new/sc-controller-0.4.7/appimage-build.sh
--- old/sc-controller-0.4.6.1/appimage-build.sh 2018-12-21 00:20:53.000000000 
+0100
+++ new/sc-controller-0.4.7/appimage-build.sh   2019-07-08 14:28:01.000000000 
+0200
@@ -51,11 +51,11 @@
 download_dep "python-gobject-3.26.1" 
"https://archive.archlinux.org/packages/p/python2-gobject/python2-gobject-3.26.1-1-x86_64.pkg.tar.xz";
 download_dep "libpng-1.6.34" 
"https://archive.archlinux.org/packages/l/libpng/libpng-1.6.34-2-x86_64.pkg.tar.xz";
 download_dep "gdk-pixbuf-2.36.9" 
"https://archive.archlinux.org/packages/g/gdk-pixbuf2/gdk-pixbuf2-2.36.9-1-x86_64.pkg.tar.xz";
-download_dep "libcroco-0.6.12" 
"https://archive.archlinux.org/packages/l/libcroco/libcroco-0.6.12-1-x86_64.pkg.tar.xz";
+download_dep "libcroco-0.6.13" 
"https://archive.archlinux.org/packages/l/libcroco/libcroco-0.6.13-1-x86_64.pkg.tar.xz";
 download_dep "libxml2-2.9.7" 
"https://archive.archlinux.org/packages/l/libxml2/libxml2-2.9.7%2B4%2Bg72182550-2-x86_64.pkg.tar.xz";
 download_dep "librsvg-2.42.2" 
"https://archive.archlinux.org/packages/l/librsvg/librsvg-2%3A2.42.2-1-x86_64.pkg.tar.xz";
 download_dep "icu-60.2" 
"https://archive.archlinux.org/packages/i/icu/icu-60.2-1-x86_64.pkg.tar.xz";
-download_dep "zlib-1:1.2.9" 
"https://archive.archlinux.org/packages/z/zlib/zlib-1%3A1.2.9-1-x86_64.pkg.tar.xz";
+download_dep "zlib-1:1.2.11" 
"https://archive.archlinux.org/packages/z/zlib/zlib-1%3A1.2.11-1-x86_64.pkg.tar.xz";
 
 # Prepare & build deps
 export PYTHONPATH=${BUILD_APPDIR}/usr/lib/python2.7/site-packages/
@@ -72,11 +72,11 @@
 unpack_dep "libpng-1.6.34"
 unpack_dep "python-gobject-3.26.1"
 unpack_dep "gdk-pixbuf-2.36.9"
-unpack_dep "libcroco-0.6.12"
+unpack_dep "libcroco-0.6.13"
 unpack_dep "libxml2-2.9.7"
 unpack_dep "librsvg-2.42.2"
 unpack_dep "icu-60.2"
-unpack_dep "zlib-1:1.2.9"
+unpack_dep "zlib-1:1.2.11"
 
 # Remove uneeded files
 rm -f 
"${BUILD_APPDIR}/usr/${LIB}/gdk-pixbuf-2.0/2.10.0/loaders/libpixbufloader-ani.so"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/sc-controller-0.4.6.1/default_profiles/Desktop.sccprofile 
new/sc-controller-0.4.7/default_profiles/Desktop.sccprofile
--- old/sc-controller-0.4.6.1/default_profiles/Desktop.sccprofile       
2018-12-21 00:20:53.000000000 +0100
+++ new/sc-controller-0.4.7/default_profiles/Desktop.sccprofile 2019-07-08 
14:28:01.000000000 +0200
@@ -38,7 +38,9 @@
     "cpad": {
         "action": "mouse()"
     }, 
-    "gyro": {}, 
+    "gyro": {
+       "action": "cemuhook"
+    }, 
     "is_template": false, 
     "menus": {}, 
     "pad_left": {
@@ -57,4 +59,4 @@
         "action": "button(Keys.BTN_LEFT)"
     }, 
     "version": 1.4
-}
\ No newline at end of file
+}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' "old/sc-controller-0.4.6.1/default_profiles/XBox 
Controller.sccprofile" "new/sc-controller-0.4.7/default_profiles/XBox 
Controller.sccprofile"
--- "old/sc-controller-0.4.6.1/default_profiles/XBox Controller.sccprofile"     
2018-12-21 00:20:53.000000000 +0100
+++ "new/sc-controller-0.4.7/default_profiles/XBox Controller.sccprofile"       
2019-07-08 14:28:01.000000000 +0200
@@ -42,7 +42,9 @@
         }
     }, 
     "cpad": {}, 
-    "gyro": {}, 
+    "gyro": {
+       "action": "cemuhook"
+    }, 
     "is_template": false, 
     "menus": {}, 
     "pad_left": {
@@ -61,4 +63,4 @@
         "action": "axis(Axes.ABS_RZ)"
     }, 
     "version": 1.4
-}
\ No newline at end of file
+}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/sc-controller-0.4.6.1/docs/actions.md 
new/sc-controller-0.4.7/docs/actions.md
--- old/sc-controller-0.4.6.1/docs/actions.md   2018-12-21 00:20:53.000000000 
+0100
+++ new/sc-controller-0.4.7/docs/actions.md     2019-07-08 14:28:01.000000000 
+0200
@@ -153,6 +153,11 @@
 Resets gyroscope offsets so current orientation is treated as neutral.
 
 
+#### <a name="cemuhook"></a> cemuhook()
+When set to gyro, outputs gyroscope data in way compatibile with Cemu, Citra 
and
+other applications using CemuHookUDP motion provider protocol.
+
+
 #### <a name="tilt"></a> gyro(front_down, front_up, tilt_left, tilt_right)
 Maps tilting of gamepad into actions. When gamepad is tilt to one of for 
supported
 sides, assigned action is executed as if by button press and then "released" 
after
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/sc-controller-0.4.6.1/glade/about.glade 
new/sc-controller-0.4.7/glade/about.glade
--- old/sc-controller-0.4.6.1/glade/about.glade 2018-12-21 00:20:53.000000000 
+0100
+++ new/sc-controller-0.4.7/glade/about.glade   2019-07-08 14:28:01.000000000 
+0200
@@ -117,11 +117,11 @@
 I'd like to express my biggest thanks
 for all my &lt;b&gt;&lt;a 
href="https://www.patreon.com/kozec"&gt;Patreon&lt;/a&gt;&lt;/b&gt; supporters, 
with special mention of
 
-&lt;b&gt;Deryn L.&lt;/b&gt;
-&lt;b&gt;Eric Duhamel&lt;/b&gt;
-&lt;b&gt;Enric Morales&lt;/b&gt;
+&lt;b&gt;guido haag&lt;/b&gt;
 &lt;b&gt;Orivej Desh&lt;/b&gt;
 &lt;b&gt;G. Wilson&lt;/b&gt;
+&lt;b&gt;Eric Duhamel&lt;/b&gt;
+&lt;b&gt;Enric Morales&lt;/b&gt;
 &lt;b&gt;Joshua M&lt;/b&gt;
 &lt;b&gt;Lutris&lt;/b&gt;
 &lt;b&gt;Taowa&lt;/b&gt;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/sc-controller-0.4.6.1/glade/ae/gyro_action.glade 
new/sc-controller-0.4.7/glade/ae/gyro_action.glade
--- old/sc-controller-0.4.6.1/glade/ae/gyro_action.glade        2018-12-21 
00:20:53.000000000 +0100
+++ new/sc-controller-0.4.7/glade/ae/gyro_action.glade  2019-07-08 
14:28:01.000000000 +0200
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<!-- Generated with glade 3.22.1 -->
+<!-- Generated with glade 3.20.4 -->
 <interface>
   <requires lib="gtk+" version="3.10"/>
   <object class="GtkAdjustment" id="adjSoftLevel">
@@ -67,6 +67,11 @@
         <col id="1" translatable="yes">Left Stick (Absolute)</col>
         <col id="2">left_abs</col>
       </row>
+      <row>
+        <col id="0">cemuhook</col>
+        <col id="1" translatable="yes">CemuHook motion provider</col>
+        <col id="2">cemuhook</col>
+      </row>
     </data>
   </object>
   <object class="GtkListStore" id="lstYawRoll">
@@ -95,7 +100,7 @@
     <property name="row_spacing">3</property>
     <property name="column_spacing">10</property>
     <child>
-      <object class="GtkLabel" id="label1">
+      <object class="GtkLabel" id="lblYawRoll">
         <property name="visible">True</property>
         <property name="can_focus">False</property>
         <property name="margin_left">5</property>
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/sc-controller-0.4.6.1/run.sh 
new/sc-controller-0.4.7/run.sh
--- old/sc-controller-0.4.6.1/run.sh    2018-12-21 00:20:53.000000000 +0100
+++ new/sc-controller-0.4.7/run.sh      2019-07-08 14:28:01.000000000 +0200
@@ -1,9 +1,10 @@
 #!/bin/bash
-C_MODULES=(uinput hiddrv sc_by_bt remotepad)
+C_MODULES=(uinput hiddrv sc_by_bt remotepad cemuhook)
 C_VERSION_uinput=9
 C_VERSION_hiddrv=5
 C_VERSION_sc_by_bt=3
 C_VERSION_remotepad=1
+C_VERSION_cemuhook=1
 
 function rebuild_c_modules() {
        echo "lib$1.so is outdated or missing, building one"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/sc-controller-0.4.6.1/scc/actions.py 
new/sc-controller-0.4.7/scc/actions.py
--- old/sc-controller-0.4.6.1/scc/actions.py    2018-12-21 00:20:53.000000000 
+0100
+++ new/sc-controller-0.4.7/scc/actions.py      2019-07-08 14:28:01.000000000 
+0200
@@ -535,6 +535,7 @@
        to actually do something.
        """
        SA = ""
+       
        def execute_named(self, name, mapper, *a):
                sa = mapper.get_special_actions_handler()
                h_name = "on_sa_%s" % (name,)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/sc-controller-0.4.6.1/scc/c_branch.h 
new/sc-controller-0.4.7/scc/c_branch.h
--- old/sc-controller-0.4.6.1/scc/c_branch.h    1970-01-01 01:00:00.000000000 
+0100
+++ new/sc-controller-0.4.7/scc/c_branch.h      2019-07-08 14:28:01.000000000 
+0200
@@ -0,0 +1,22 @@
+/**
+ * Glue between code from future and current stuff in python
+ */
+#pragma once
+#include "Python.h"
+#include <stdbool.h>
+#include <stdint.h>
+
+#define LERROR(fmt, ...) do { fprintf(stderr, "E " LOG_TAG " " fmt, 
##__VA_ARGS__); fprintf(stderr, "\n"); fflush(stderr); } while(0)
+#define WARN(fmt, ...) do { fprintf(stderr, "W " LOG_TAG " " fmt, 
##__VA_ARGS__); fprintf(stderr, "\n"); fflush(stderr); } while(0)
+#define DEBUG(fmt, ...) do { fprintf(stdout, "D " LOG_TAG " " fmt, 
##__VA_ARGS__); fprintf(stdout, "\n"); fflush(stdout); } while(0)
+#define LOG(fmt, ...) do { fprintf(stdout, "L " LOG_TAG " " fmt, 
##__VA_ARGS__); fprintf(stdout, "\n"); fflush(stdout); } while(0)
+
+typedef uint64_t monotime_t;
+
+/** Returns current value of CLOCK_MONOTONIC converted to number of 
milliseconds */
+inline static uint64_t mono_time_ms() {
+       static struct timespec t;
+       clock_gettime(CLOCK_MONOTONIC, &t);
+       return t.tv_sec * 1000 + (t.tv_nsec / 10e5);
+}
+
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/sc-controller-0.4.6.1/scc/cemuhook_server.c 
new/sc-controller-0.4.7/scc/cemuhook_server.c
--- old/sc-controller-0.4.6.1/scc/cemuhook_server.c     1970-01-01 
01:00:00.000000000 +0100
+++ new/sc-controller-0.4.7/scc/cemuhook_server.c       2019-07-08 
14:28:01.000000000 +0200
@@ -0,0 +1,395 @@
+/**
+ * SC-Controller - Daemon - CemuHookUDP motion provider
+ *
+ * Accepts all connections from clients and sends data captured
+ * by 'cemuhook' actions to them.
+ *
+ * This code is also used as library in Python code in master branch.
+ */
+
+#define LOG_TAG "CemuHook"
+#ifndef PYTHON
+       #include "scc/utils/logging.h"
+       #include "scc/utils/strbuilder.h"
+       #include "scc/utils/iterable.h"
+       #include "scc/utils/assert.h"
+       #include "scc/utils/math.h"
+       #include "scc/utils/list.h"
+       #include "scc/tools.h"
+       #include "daemon.h"
+#else  // PYTHON
+       #undef LOG_TAG
+       #define LOG_TAG "CemuHook     "
+       #include "c_branch.h"
+#endif // PYTHON
+#ifdef _WIN32
+       #error "Implement me!"
+#else  // _WIN32
+       #include <netinet/in.h>
+       #include <sys/socket.h>
+       #include <arpa/inet.h>
+       #include <sys/types.h>
+       #define SOCKETERROR  ": %s", strerror(errno)
+#endif // _WIN32
+#include <stdbool.h>
+#include <stdint.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <errno.h>
+#include <zlib.h>
+
+#define BUFFER_SIZE                                    1024
+#define MAX_PROTO_VERSION                      1001
+#define CLIENT_TIMEOUT                         (5 * 1000)
+#define CEMUHOOK_MODULE_VERSION                1
+typedef struct CEHClient {
+       struct sockaddr_in      address;
+       monotime_t                      last_seen;
+       uint32_t                        next_packet_no;
+} CEHClient;
+static uint32_t next_id = 1;
+#ifndef PYTHON
+static LIST_TYPE(CEHClient) clients;
+static int sock;
+#else
+#define CLIENT_LIMIT                           10
+static CEHClient clients[CLIENT_LIMIT];
+#endif
+
+
+typedef enum {
+       DSUC_VERSIONREQ =       0x100000,
+       DSUS_VERSIONRSP =       0x100000,
+       DSUC_LISTPORTS =        0x100001,
+       DSUS_PORTINFO =         0x100001,
+       DSUC_PADDATAREQ =       0x100002,
+       DSUS_PADDATARSP =       0x100002,
+} MessageType;
+
+struct __attribute__((packed)) PortInfo {
+       uint8_t                 pad_id;
+       uint8_t                 state;
+       uint8_t                 model;
+       uint8_t                 connection_type;
+       uint8_t                 mac[6];
+       uint8_t                 battery;
+       uint8_t                 active;
+};
+
+struct __attribute__((packed)) Message {
+       char                                            header[4];              
        // 0B
+       uint16_t                                        protocol_version;       
// 4B
+       uint16_t                                        packet_size;            
// 6B
+       uint32_t                                        crc;                    
        // 8B
+       uint32_t                                        msg_id;                 
        // 12B
+       MessageType                                     message_type;           
// 16B
+       union {                                                                 
                // 20B
+               struct {
+                       int32_t                         count;
+                       uint8_t                         ids[4];
+               } list_ports;
+               struct {
+                       uint8_t                         flags;
+                       uint8_t                         id;
+                       uint8_t                         mac[6];
+               } pad_data_req;
+               struct {
+                       uint16_t                        max_version;
+                       uint16_t                        min_version;
+               } version_info;
+               struct PortInfo                 port_info[4];           // size 
= 12B * 4B
+               struct {
+                       struct PortInfo         pad_info;
+                       uint32_t                        packet_number;
+                       uint8_t                         buttons1;
+                       uint8_t                         buttons2;
+                       uint8_t                         button_ps;
+                       uint8_t                         button_touch;
+                       uint8_t                         sticks[4];              
        // LX, LY, RX, RY
+                       uint8_t                         analog_buttons[12];
+                       struct {
+                               uint8_t                 active;
+                               uint8_t                 id;
+                               uint16_t                x;
+                               uint16_t                y;
+                       } touch_point[2];
+                       uint64_t                        motion_timestamp;
+                       struct {
+                               float                   x;
+                               float                   y;
+                               float                   z;
+                               float                   pitch;
+                               float                   yaw;
+                               float                   roll;
+                       } accel;
+               } pad_data;
+       };
+};
+
+static void send_msg(int fd, struct sockaddr_in* target, struct Message* msg, 
MessageType type, uint16_t payload_size) {
+       size_t size = 20 + payload_size;
+       memcpy(msg->header, "DSUS", 4);
+       msg->protocol_version = MAX_PROTO_VERSION;
+       msg->packet_size = 4 + payload_size;
+       msg->message_type = type;
+       msg->msg_id = next_id ++;
+       msg->crc = 0;
+       
+       uLong crc = crc32(0, (const Bytef*)msg, size);
+       msg->crc = crc;
+       
+       ssize_t r = sendto(fd, (char*)msg, size, 0, (struct sockaddr*)target, 
sizeof(struct sockaddr_in));
+       if (r < 0) LERROR("sendto failed: " SOCKETERROR);
+}
+
+static void fill_port_info(struct PortInfo* pi, uint16_t id, uint8_t active) {
+       static uint8_t mac[6] = { 0x05, 0x0C, 0x0C, 0x00, 0x00, 0x01 };
+       pi->pad_id = id;
+       pi->state = (id == 0) ? 0x02 : 0x00;    // Connected : Disconnected
+       pi->connection_type = 0x01;                             // Usb
+       pi->model = 0x02;                                               // DS4
+       pi->battery = 0x04;                                             // High
+       pi->active = active;
+       memcpy(pi->mac, mac, 5);
+       pi->mac[5] = 1 + id;
+}
+
+static void send_gyro_data(int fd, CEHClient* target, uint16_t id, float 
data[6], uint64_t timestamp) {
+       struct Message out;
+       memset(&out, 0, sizeof(struct Message));
+       fill_port_info(&out.pad_data.pad_info, id, 1);
+       memcpy(&out.pad_data.accel, data, sizeof(float) * 6);
+       out.pad_data.motion_timestamp = timestamp * 1000;
+       out.pad_data.packet_number = target->next_packet_no ++;
+       send_msg(fd, &target->address, &out, DSUS_PADDATARSP, 80);
+       // DEBUG("Sent data to (0x%x)", target->address.sin_port);
+}
+
+static void parse_message(int fd, const char* buffer, size_t size, struct 
sockaddr_in* source) {
+       struct Message* msg = (struct Message*)&buffer[0];
+       struct Message out;
+       int i, x;
+       if ((size < 20) || (buffer[0] != 'D') || (buffer[1]!='S') || (buffer[2] 
!= 'U') || (buffer[3] != 'C')) {
+               WARN("Recieved invalid message: Invalid header");
+               return;
+       }
+       if (msg->protocol_version > MAX_PROTO_VERSION) {
+               WARN("Recieved invalid message: Unsupported version");
+               return;
+       }
+       if (size < msg->packet_size + 20 - 4) {
+               WARN("Recieved invalid message: Invalid size (expected %i, got 
%i)", msg->packet_size + 20 - 4, size);
+               return;
+       }
+       
+       switch (msg->message_type) {
+       case DSUC_VERSIONREQ:
+               out.version_info.min_version = 0;
+               out.version_info.max_version = MAX_PROTO_VERSION;
+               send_msg(fd, source, &out, DSUS_VERSIONRSP, 4);
+               break;
+       case DSUC_LISTPORTS:
+               if ((msg->list_ports.count > 0) && (msg->list_ports.count <= 
4)) {
+                       for (i=0; i<msg->list_ports.count; i++)
+                               fill_port_info(&out.port_info[i], 
msg->list_ports.ids[i], 0);
+                       send_msg(fd, source, &out, DSUS_PORTINFO, 12 * 
msg->list_ports.count);
+               }
+               break;
+       case DSUC_PADDATAREQ: {
+               if (!((msg->pad_data_req.flags == 0)
+                       || (((msg->pad_data_req.flags & 0x01) != 0) && 
(msg->pad_data_req.id == 0)))) {
+                               // Only querying by ID and querying for 1st 
controller is supported
+                               WARN("Refusing request: flags=%x id=%x 
mac=%x:%x:%x:%x:%x:%x",
+                                               msg->pad_data_req.flags, 
msg->pad_data_req.id,
+                                               msg->pad_data_req.mac[0],
+                                               msg->pad_data_req.mac[1],
+                                               msg->pad_data_req.mac[2],
+                                               msg->pad_data_req.mac[3],
+                                               msg->pad_data_req.mac[4],
+                                               msg->pad_data_req.mac[5]
+                               );
+                               break;
+               }
+               CEHClient* c = NULL;
+#ifdef PYTHON
+               for (x=0; x<CLIENT_LIMIT; x++) {
+                       if (clients[x].address.sin_port == 0)
+                               continue;
+                       CEHClient* i = &clients[x];
+#else
+               FOREACH_IN(CEHClient*, i, clients) {
+#endif
+                       if (i->address.sin_port == source->sin_port) {
+                               // Server listens only on localhost, so it 
should be safe to assume IP matches
+                               c = i;
+                               break;
+                       }
+               }
+               if (c == NULL) {
+#ifdef PYTHON
+                       for (x=0; x<CLIENT_LIMIT; x++) {
+                               if (clients[x].address.sin_port == 0) {
+                                       c = &clients[x];
+                               }
+                       }
+                       if (c == NULL) {
+                               WARN("Client limit reached");
+                               break;
+                       }
+#else
+                       c = malloc(sizeof(CEHClient));
+                       if ((c == NULL) || (!list_allocate(clients, 1))) {
+                               WARN("Out of memory");
+                               free(c);
+                               break;
+                       }
+                       list_add(clients, c);
+#endif
+                       memcpy(&c->address, source, sizeof(struct sockaddr_in));
+                       c->next_packet_no = mono_time_ms() & 0xFFFFFFFF;
+                       DEBUG("New client (0x%x) added", c->address.sin_port);
+               }
+               c->last_seen = mono_time_ms();
+               break;
+       }
+       default:
+               // WARN("Recieved invalid message: Unknown message type");
+               return;
+       }
+}
+
+#ifdef PYTHON
+bool cemuhook_feed(int fd, int index, float data[6]) {
+#else
+bool sccd_cemuhook_feed(int index, float data[6]) {
+       const int fd = sock;
+#endif
+       monotime_t t = mono_time_ms();
+#ifdef PYTHON
+       int x;
+       for (x=0; x<CLIENT_LIMIT; x++) {
+               CEHClient* c = &clients[x];
+               if (c->address.sin_port == 0)
+                       continue;
+#else
+       ListIterator it = iter_get(clients);
+       if (it == NULL) return false;   // OOM
+       while (iter_has_next(it)) {
+               CEHClient* c = iter_next(it);
+#endif
+               if ((t > c->last_seen + CLIENT_TIMEOUT) || (t < c->last_seen)) {
+                       DEBUG("Dropping client (0x%x)", c->address.sin_port);
+                       c->address.sin_port = 0;
+#ifndef PYTHON
+                       iter_remove(it);
+#endif
+               } else {
+                       send_gyro_data(fd, c, 0, data, (uint64_t)t);
+               }
+       }
+#ifndef PYTHON
+       iter_free(it);
+#endif
+       return true;
+}
+
+#ifdef PYTHON
+
+const int cemuhook_module_version(void) {
+       return CEMUHOOK_MODULE_VERSION;
+}
+
+void cemuhook_data_recieved(int fd, int port, const char* buffer, size_t size) 
{
+       struct sockaddr_in source;
+       source.sin_family = AF_INET;
+       source.sin_addr.s_addr = inet_addr("127.0.0.1");
+       source.sin_port = htons(port);
+       
+       parse_message(fd, buffer, size, &source);
+}
+
+bool cemuhook_socket_enable() {
+       int i;
+       for (i=0; i<CLIENT_LIMIT; i++)
+               clients[i].address.sin_port = 0;
+       // listening is done in python
+       return true;
+}
+
+#else
+
+static void on_data_recieved(Daemon* d, int fd, void* userdata) {
+       char buffer[BUFFER_SIZE];
+       struct sockaddr_in source;
+       socklen_t len = sizeof(struct sockaddr_in);
+       ssize_t n = recvfrom(fd, buffer, BUFFER_SIZE, 0, (struct 
sockaddr*)&source, &len);
+       
+       if (n < 0) {
+               LERROR("recvfrom: " SOCKETERROR);
+               return;
+       }
+       
+       parse_message(sock, buffer, n, &source);
+}
+
+
+bool sccd_cemuhook_socket_enable() {
+       clients = list_new(CEHClient, 4);
+       if (clients == NULL)
+               // This may be enabled at random time, so I can't just crash 
here
+               return false;
+       
+       struct sockaddr_in server_addr;
+       memset(&server_addr, 0, sizeof(struct sockaddr_in));
+       server_addr.sin_family = AF_INET;
+       server_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
+       server_addr.sin_port = htons(26760);
+       
+#ifdef _WIN32
+       WSADATA wsaData;
+       int err = WSAStartup(MAKEWORD(2, 2), &wsaData);
+       if (err != 0) {
+               LERROR("Failed to initialize Winsock2: error %i", err);
+               return false;
+       }
+#endif
+       sock = socket(AF_INET, SOCK_DGRAM, 0);
+       if (sock < 0) {
+               LERROR("Failed to open control socket" SOCKETERROR);
+               return false;
+       }
+       
+       /*
+#ifndef _WIN32
+       if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &(int){ 1 }, 
sizeof(int)) < 0) {
+#else
+       if (setsockopt(sock, SOL_SOCKET, SO_EXCLUSIVEADDRUSE, &(char){ 1 }, 
sizeof(char)) < 0) {
+#endif
+               // stupid, but not fatal
+               WARN("setsockopt failed" SOCKETERROR);
+       }
+       */
+       if (bind(sock, (const struct sockaddr *)&server_addr, sizeof(struct 
sockaddr_in)) < 0) {
+               LERROR("Bind failed" SOCKETERROR);
+               return false;
+       }
+       
+       if (!sccd_poller_add(sock, &on_data_recieved, NULL)) {
+               LERROR("sccd_poller_add failed to add listening socket");
+               return false;
+       }
+       
+       LOG("Created CemuHookUDP Motion Provider");
+       return true;
+}
+
+
+__attribute__((constructor)) void check_stuff() {
+       ASSERT(sizeof(MessageType) == sizeof(uint32_t));
+       ASSERT(sizeof(float) == 4);
+}
+
+#endif
+
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/sc-controller-0.4.6.1/scc/cemuhook_server.py 
new/sc-controller-0.4.7/scc/cemuhook_server.py
--- old/sc-controller-0.4.6.1/scc/cemuhook_server.py    1970-01-01 
01:00:00.000000000 +0100
+++ new/sc-controller-0.4.7/scc/cemuhook_server.py      2019-07-08 
14:28:01.000000000 +0200
@@ -0,0 +1,66 @@
+#!/usr/bin/env python2
+"""
+SC-Controller - Daemon - CemuHookUDP motion provider
+
+Accepts all connections from clients and sends data captured
+by 'cemuhook' actions to them.
+"""
+from __future__ import unicode_literals
+from scc.tools import find_library
+from scc.lib.enum import IntEnum
+from ctypes import c_uint32, c_int, c_bool, c_char_p, c_size_t, c_float
+from ctypes import create_string_buffer
+import logging, socket
+log = logging.getLogger("CemuHook")
+
+BUFFER_SIZE = 1024
+PORT = 26760
+
+
+class MessageType(IntEnum):
+       DSUC_VERSIONREQ =       0x100000
+       DSUS_VERSIONRSP =       0x100000
+       DSUC_LISTPORTS =        0x100001
+       DSUS_PORTINFO =         0x100001
+       DSUC_PADDATAREQ =       0x100002
+       DSUS_PADDATARSP =       0x100002
+
+
+class CemuhookServer:
+       C_DATA_T = c_float * 6
+       
+       def __init__(self, daemon):
+               self._lib = find_library('libcemuhook')
+               self._lib.cemuhook_data_recieved.argtypes = [ c_int, c_int, 
c_char_p, c_size_t ]
+               self._lib.cemuhook_data_recieved.restype = None
+               self._lib.cemuhook_feed.argtypes = [ c_int, c_int, 
CemuhookServer.C_DATA_T ]
+               self._lib.cemuhook_feed.restype = None
+               self._lib.cemuhook_socket_enable.argtypes = []
+               self._lib.cemuhook_socket_enable.restype = c_bool
+               
+               if not self._lib.cemuhook_socket_enable():
+                       raise OSError("cemuhook_socket_enable failed")
+               
+               self.socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
+               self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 
1)
+               
+               poller = daemon.get_poller()
+               daemon.poller.register(self.socket.fileno(), poller.POLLIN, 
self.on_data_recieved)
+               
+               self.socket.bind(('127.0.0.1', 26760))
+               log.info("Created CemuHookUDP Motion Provider")
+       
+       
+       def on_data_recieved(self, fd, event_type):
+               if fd != self.socket.fileno(): return
+               message, (ip, port) = self.socket.recvfrom(BUFFER_SIZE)
+               buffer = create_string_buffer(BUFFER_SIZE)
+               self._lib.cemuhook_data_recieved(fd, port, message, 
len(message), buffer)
+       
+       
+       def feed(self, data):
+               c_data = CemuhookServer.C_DATA_T()
+               c_data[3:6] = data[0:3]
+               self._lib.cemuhook_feed(self.socket.fileno(), 0, c_data)
+
+
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/sc-controller-0.4.6.1/scc/constants.py 
new/sc-controller-0.4.7/scc/constants.py
--- old/sc-controller-0.4.6.1/scc/constants.py  2018-12-21 00:20:53.000000000 
+0100
+++ new/sc-controller-0.4.7/scc/constants.py    2019-07-08 14:28:01.000000000 
+0200
@@ -28,7 +28,7 @@
 If SC-Controller is updated while daemon is running, DAEMON_VERSION send by
 daemon will differ one one expected by UI and daemon will be forcefully 
restarted.
 """
-DAEMON_VERSION = "0.4.6"
+DAEMON_VERSION = "0.4.7"
 
 HPERIOD  = 0.02
 LPERIOD  = 0.5
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/sc-controller-0.4.6.1/scc/gui/action_editor.py 
new/sc-controller-0.4.7/scc/gui/action_editor.py
--- old/sc-controller-0.4.6.1/scc/gui/action_editor.py  2018-12-21 
00:20:53.000000000 +0100
+++ new/sc-controller-0.4.7/scc/gui/action_editor.py    2019-07-08 
14:28:01.000000000 +0200
@@ -1183,3 +1183,4 @@
                        rvMore.set_reveal_child(False)
                exMore.set_sensitive(enabled)
                self._modifiers_enabled = enabled
+
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/sc-controller-0.4.6.1/scc/gui/ae/axis_action.py 
new/sc-controller-0.4.7/scc/gui/ae/axis_action.py
--- old/sc-controller-0.4.6.1/scc/gui/ae/axis_action.py 2018-12-21 
00:20:53.000000000 +0100
+++ new/sc-controller-0.4.7/scc/gui/ae/axis_action.py   2019-07-08 
14:28:01.000000000 +0200
@@ -482,7 +482,7 @@
                        action = self.make_circular_action()
                elif key == 'mouse':
                        
stActionData.set_visible_child(self.builder.get_object("vbMose"))
-                       if self.editor.friction == 0:
+                       if not self._recursing and self.editor.friction == 0:
                                # When switching to mouse, enable trackball by 
default
                                self.editor.friction = 10
                        action = self.make_mouse_action()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/sc-controller-0.4.6.1/scc/gui/ae/gyro_action.py 
new/sc-controller-0.4.7/scc/gui/ae/gyro_action.py
--- old/sc-controller-0.4.6.1/scc/gui/ae/gyro_action.py 2018-12-21 
00:20:53.000000000 +0100
+++ new/sc-controller-0.4.7/scc/gui/ae/gyro_action.py   2019-07-08 
14:28:01.000000000 +0200
@@ -7,6 +7,7 @@
 
 from scc.actions import Action, NoAction, MouseAction, MultiAction, RangeOP
 from scc.actions import GyroAction, GyroAbsAction, MouseAbsAction
+from scc.special_actions import CemuHookAction
 from scc.modifiers import ModeModifier, SensitivityModifier
 from scc.uinput import Axes, Rels
 from scc.constants import SCButtons, STICK, YAW, ROLL
@@ -118,6 +119,8 @@
                                                self.select_gyro_output("right")
                                elif ap[0] == Rels.REL_Y and ap[-1] == 
Rels.REL_X:
                                        self.select_gyro_output("mouse_stick")
+                       elif isinstance(action, CemuHookAction):
+                                       self.select_gyro_output("cemuhook")
                        self.modifier_updated()
        
        
@@ -129,6 +132,8 @@
                        self._recursing = True
                        cbInvertY.set_active(inverted)
                        self._recursing = False
+
+               self.update()
        
        
        def cbInvertY_toggled_cb(self, cb, *a):
@@ -164,7 +169,7 @@
                                elif ap[0] == Rels.REL_Y and ap[-1] == 
Rels.REL_X:
                                        return True
                        return False
-               if isinstance(action, (MouseAction, MouseAbsAction)):
+               if isinstance(action, (MouseAction, MouseAbsAction, 
CemuHookAction)):
                        return True
                return False
        
@@ -232,7 +237,12 @@
        
        
        def update(self, *a):
-               pass
+               cbMode = self.builder.get_object("cbMode")
+               cbYawRoll = self.builder.get_object("cbYawRoll")
+               lblYawRoll = self.builder.get_object("lblYawRoll")
+               key = cbMode.get_model().get_value(cbMode.get_active_iter(), 2)
+               cbYawRoll.set_sensitive(key != "cemuhook")
+               lblYawRoll.set_sensitive(key != "cemuhook")     
        
        
        def hidden(self):
@@ -248,6 +258,7 @@
                sclSoftLevel = self.builder.get_object("sclSoftLevel")
                cbGyroButton = self.builder.get_object("cbGyroButton")
                cbInvertGyro = self.builder.get_object("cbInvertGyro")
+               cbInvertGyro = self.builder.get_object("cbInvertGyro")
                action = cbMode.get_model().get_value(cbMode.get_active_iter(), 
0)
                key = cbMode.get_model().get_value(cbMode.get_active_iter(), 2)
                yawroll = 
cbYawRoll.get_model().get_value(cbYawRoll.get_active_iter(), 0)
@@ -279,6 +290,7 @@
                else:
                        self.editor.set_default_sensitivity(1, 1, 1)
                
+               self.update()
                self.editor.set_action(action)
 
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/sc-controller-0.4.6.1/scc/gui/app.py 
new/sc-controller-0.4.7/scc/gui/app.py
--- old/sc-controller-0.4.6.1/scc/gui/app.py    2018-12-21 00:20:53.000000000 
+0100
+++ new/sc-controller-0.4.7/scc/gui/app.py      2019-07-08 14:28:01.000000000 
+0200
@@ -1040,7 +1040,7 @@
                elif "LIBUSB_ERROR_ACCESS" in error:
                        msg += "\n" + _("You don't have access to controller 
device.")
                        msg += "\n\n" + ( _("Consult your distribution manual, 
try installing Steam package or <a href='%s'>install required udev rules 
manually</a>.") %
-                                       
'https://wiki.archlinux.org/index.php/Gamepad#Steam_Controller_Not_Pairing' )
+                                       
'https://wiki.archlinux.org/index.php/Gamepad#Steam_Controller_not_pairing' )
                        # TODO: Write howto somewhere instead of linking to 
ArchWiki
                elif "LIBUSB_ERROR_BUSY" in error:
                        msg += "\n" + _("Another application (most likely 
Steam) is using the controller.")
@@ -1351,6 +1351,10 @@
        
        def do_activate(self, *a):
                self.builder.get_object("window").show()
+               if self.config['gui']['minimize_on_start'] and 
self.statusicon.get_property("active"):
+                       self.builder.get_object("window").hide()
+               else:
+                       self.builder.get_object("window").show()
        
        
        def remove_dot_profile(self):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/sc-controller-0.4.6.1/scc/gui/creg/dialog.py 
new/sc-controller-0.4.7/scc/gui/creg/dialog.py
--- old/sc-controller-0.4.6.1/scc/gui/creg/dialog.py    2018-12-21 
00:20:53.000000000 +0100
+++ new/sc-controller-0.4.7/scc/gui/creg/dialog.py      2019-07-08 
14:28:01.000000000 +0200
@@ -25,7 +25,7 @@
 from scc.config import Config
 
 import evdev
-import os, logging, json
+import os, logging, json, re
 log = logging.getLogger("CRegistration")
 
 
@@ -84,14 +84,18 @@
                Device is considered gamepad-like if has at least one button 
with
                keycode in gamepad range and at least two axes.
                """
+
+               # Strip special symbols
+               name = re.sub( r"[^a-zA-Z0-9.]+", ' ', dev.name.lower() )
+
                # ... but some cheating first
-               if "keyboard" in dev.name.lower():
+               if "keyboard" in name:
                        return False
-               if "touchpad" in dev.name.lower():
+               if "touchpad" in name:
                        return False
-               if "mouse" in dev.name.lower():
+               if "mouse" in name:
                        return False
-               if "gamepad" in dev.name.lower():
+               if "gamepad" in name:
                        return True
                caps = dev.capabilities(verbose=False)
                if evdev.ecodes.EV_ABS in caps: # Has axes
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/sc-controller-0.4.6.1/scc/gui/dwsnc.py 
new/sc-controller-0.4.7/scc/gui/dwsnc.py
--- old/sc-controller-0.4.6.1/scc/gui/dwsnc.py  2018-12-21 00:20:53.000000000 
+0100
+++ new/sc-controller-0.4.7/scc/gui/dwsnc.py    2019-07-08 14:28:01.000000000 
+0200
@@ -38,35 +38,41 @@
 
 IS_UNITY = False
 IS_GNOME = False
+IS_KDE = False
 
-if "XDG_CURRENT_DESKTOP" in os.environ and "GNOME" in 
os.environ["XDG_CURRENT_DESKTOP"].split(":"):
-       IS_GNOME = True
-
-if "XDG_CURRENT_DESKTOP" in os.environ and "Unity" in 
os.environ["XDG_CURRENT_DESKTOP"].split(":"):
-       # User runs Unity
-       IS_UNITY = True
+if "XDG_CURRENT_DESKTOP" in os.environ:
+       if "GNOME" in os.environ["XDG_CURRENT_DESKTOP"].split(":"):
+               IS_GNOME = True
+       
+       if "KDE" in os.environ["XDG_CURRENT_DESKTOP"].split(":"):
+               IS_KDE = True
        
-       def _headerbar(bar):
-               children = [] + bar.get_children()
-               pack_start = []
-               pack_end = []
-               for c in children:
-                       if child_get_property(bar, c, 'pack-type') == 
Gtk.PackType.END:
-                               bar.remove(c)
-                               pack_start.append(c)
-                       else:
-                               bar.remove(c)
+       if "Unity" in os.environ["XDG_CURRENT_DESKTOP"].split(":"):
+               # User runs Unity
+               IS_UNITY = True
+               
+               def _headerbar(bar):
+                       children = [] + bar.get_children()
+                       pack_start = []
+                       pack_end = []
+                       for c in children:
+                               if child_get_property(bar, c, 'pack-type') == 
Gtk.PackType.END:
+                                       bar.remove(c)
+                                       pack_start.append(c)
+                               else:
+                                       bar.remove(c)
+                                       pack_end.append(c)
+                       if len(pack_end) > 1:
+                               c,  pack_end = pack_end[0], pack_end[1:]
                                pack_end.append(c)
-               if len(pack_end) > 1:
-                       c,  pack_end = pack_end[0], pack_end[1:]
-                       pack_end.append(c)
-               if (Gtk.get_major_version(), Gtk.get_minor_version()) > (3, 10):
-                       # Old ubuntu has this in order, new Ubuntu has it 
reversed
-                       pack_end = reversed(pack_end)
-               for c in pack_start: bar.pack_start(c)
-               for c in pack_end: bar.pack_end(c)
-       headerbar = _headerbar
+                       if (Gtk.get_major_version(), Gtk.get_minor_version()) > 
(3, 10):
+                               # Old ubuntu has this in order, new Ubuntu has 
it reversed
+                               pack_end = reversed(pack_end)
+                       for c in pack_start: bar.pack_start(c)
+                       for c in pack_end: bar.pack_end(c)
+               headerbar = _headerbar
 
 if not hasattr(Gtk.Label, "set_xalign"):
-       # GTK is old enought
+       # GTK is old enough
        fix_label_missing_set_XYalign_methods()
+
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/sc-controller-0.4.6.1/scc/gui/statusicon.py 
new/sc-controller-0.4.7/scc/gui/statusicon.py
--- old/sc-controller-0.4.6.1/scc/gui/statusicon.py     2018-12-21 
00:20:53.000000000 +0100
+++ new/sc-controller-0.4.7/scc/gui/statusicon.py       2019-07-08 
14:28:01.000000000 +0200
@@ -419,3 +419,4 @@
        
        # Use proxy backend to determine the correct backend while the 
application is running
        return StatusIconProxy(*args, **kwargs)
+
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/sc-controller-0.4.6.1/scc/mapper.py 
new/sc-controller-0.4.7/scc/mapper.py
--- old/sc-controller-0.4.6.1/scc/mapper.py     2018-12-21 00:20:53.000000000 
+0100
+++ new/sc-controller-0.4.7/scc/mapper.py       2019-07-08 14:28:01.000000000 
+0200
@@ -418,12 +418,16 @@
                                        if not self.lpad_touched:
                                                self.lpad_touched = True
                                        self.profile.pads[LEFT].whole(self, 
state.lpad_x, state.lpad_y, LEFT)
+                                       if self.old_state.buttons & STICKTILT 
and not self.buttons & STICKTILT:
+                                               # LPAD and stick share axes and 
so when they are used simultaneously (by someone with 3 hands or so :)
+                                               # this is how mapper can tell 
that stick was recentered
+                                               self.profile.stick.whole(self, 
0, 0, STICK)
                                elif not self.buttons & STICKTILT:
                                        # Pad is not being touched
                                        if self.lpad_touched:
                                                self.lpad_touched = False
                                                
self.profile.pads[LEFT].whole(self, 0, 0, LEFT)
-                       
+                                       
                        # CPAD (touchpad on DS4 controller)
                        if controller.flags & ControllerFlags.HAS_CPAD:
                                if FE_PAD in fe or self.old_state.cpad_x != 
state.cpad_x or self.old_state.cpad_y != state.cpad_y:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/sc-controller-0.4.6.1/scc/sccdaemon.py 
new/sc-controller-0.4.7/scc/sccdaemon.py
--- old/sc-controller-0.4.6.1/scc/sccdaemon.py  2018-12-21 00:20:53.000000000 
+0100
+++ new/sc-controller-0.4.7/scc/sccdaemon.py    2019-07-08 14:28:01.000000000 
+0200
@@ -13,6 +13,7 @@
 from scc.uinput import CannotCreateUInputException
 from scc.tools import set_logging_level, find_binary, clamp
 from scc.device_monitor import create_device_monitor
+from scc.cemuhook_server import CemuhookServer
 from scc.custom import load_custom_module
 from scc.gestures import GestureDetector
 from scc.parser import TalkingActionParser
@@ -63,6 +64,7 @@
                self.on_exit_cbs = []
                self.subprocs = []
                self.lock = threading.Lock()
+               self.cemuhook = None
                self.default_mapper = None
                self.free_mappers = [ ]
                self.clients = set()
@@ -276,6 +278,15 @@
                        log.debug("Gesture detection started on %s", what)
                        gd.whole(mapper, x, y, what)
        
+       def on_sa_cemuhook(self, mapper, action, data):
+               """ Called by 'cemuhook' action """
+               if self.cemuhook is None:
+                       try:
+                               self.cemuhook = CemuhookServer(self)
+                       except Exception, e:
+                               log.error("Failed to initialize CemuHookUDP 
Motion Provider: %s", e)
+                               return
+               self.cemuhook.feed(data)
        
        def _osd(self, *data):
                """
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/sc-controller-0.4.6.1/scc/special_actions.py 
new/sc-controller-0.4.7/scc/special_actions.py
--- old/sc-controller-0.4.6.1/scc/special_actions.py    2018-12-21 
00:20:53.000000000 +0100
+++ new/sc-controller-0.4.7/scc/special_actions.py      2019-07-08 
14:28:01.000000000 +0200
@@ -755,5 +755,22 @@
                        self.execute(mapper, x, y, what)
 
 
+class CemuHookAction(Action, SpecialAction):
+       SA = COMMAND = "cemuhook"
+       MAGIC_GYRO = (2000.0 / 32768.0)
+       
+       def gyro(self, mapper, *pyr):
+               sa_data = (
+                       pyr[0] * CemuHookAction.MAGIC_GYRO,
+                       -pyr[1] * CemuHookAction.MAGIC_GYRO,
+                       -pyr[2] * CemuHookAction.MAGIC_GYRO,
+               )
+               self.execute(mapper, sa_data)
+       
+       def describe(self, context):
+               if self.name: return self.name
+               return _("CemuHook")
+
 # Register actions from current module
 Action.register_all(sys.modules[__name__])
+
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/sc-controller-0.4.6.1/scripts/sc-controller.desktop 
new/sc-controller-0.4.7/scripts/sc-controller.desktop
--- old/sc-controller-0.4.6.1/scripts/sc-controller.desktop     2018-12-21 
00:20:53.000000000 +0100
+++ new/sc-controller-0.4.7/scripts/sc-controller.desktop       2019-07-08 
14:28:01.000000000 +0200
@@ -7,4 +7,4 @@
 Type=Application
 Icon=sc-controller
 Categories=GTK;Settings;HardwareSettings;
-MimeType=application/x-steamcontrollerdb-profile;application/x-scc-profile;application/x-scc-profile-package
+MimeType=application/x-steamcontrollerdb-profile;application/x-scc-profile;application/x-scc-profile-package;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/sc-controller-0.4.6.1/setup.py 
new/sc-controller-0.4.7/setup.py
--- old/sc-controller-0.4.6.1/setup.py  2018-12-21 00:20:53.000000000 +0100
+++ new/sc-controller-0.4.7/setup.py    2019-07-08 14:28:01.000000000 +0200
@@ -66,8 +66,11 @@
                        platforms = ['Linux'],
                        ext_modules = [
                                Extension('libuinput', sources = 
['scc/uinput.c']),
+                               Extension('libcemuhook', define_macros = 
[('PYTHON', 1)],
+                                                       sources = 
['scc/cemuhook_server.c'], libraries = ["z"]),
                                Extension('libhiddrv', sources = 
['scc/drivers/hiddrv.c']),
                                Extension('libsc_by_bt', sources = 
['scc/drivers/sc_by_bt.c']),
                                Extension('libremotepad', sources = 
['scc/drivers/remotepad_controller.c']),
                        ]
        )
+
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/sc-controller-0.4.6.1/tests/test_parser/test_actions.py 
new/sc-controller-0.4.7/tests/test_parser/test_actions.py
--- old/sc-controller-0.4.6.1/tests/test_parser/test_actions.py 2018-12-21 
00:20:53.000000000 +0100
+++ new/sc-controller-0.4.7/tests/test_parser/test_actions.py   2019-07-08 
14:28:01.000000000 +0200
@@ -270,8 +270,8 @@
                        AxisAction(Axes.ABS_X),
                        AxisAction(Axes.ABS_Y)
                ))
-
-
+       
+       
        def test_relXY(self):
                """
                Tests if relXYAciton can be converted to string and parsed back 
to
@@ -281,8 +281,8 @@
                        AxisAction(Axes.ABS_RX),
                        AxisAction(Axes.ABS_RY)
                ))
-
-
+       
+       
        def test_trigger(self):
                """
                Tests if TriggerAction can be converted to string and parsed 
back to
@@ -292,3 +292,4 @@
                        15, 234,
                        ButtonAction(Keys.KEY_A)
                ))
+
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/sc-controller-0.4.6.1/tests/test_parser/test_special_actions.py 
new/sc-controller-0.4.7/tests/test_parser/test_special_actions.py
--- old/sc-controller-0.4.6.1/tests/test_parser/test_special_actions.py 
2018-12-21 00:20:53.000000000 +0100
+++ new/sc-controller-0.4.7/tests/test_parser/test_special_actions.py   
2019-07-08 14:28:01.000000000 +0200
@@ -143,3 +143,11 @@
                                'LRLR', TurnOffAction()
                        )
                )
+       
+       
+       def test_cemuhook(self):
+               """
+               Nothing to test here
+               """
+               pass
+
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/sc-controller-0.4.6.1/tests/test_profile/test_special_actions.py 
new/sc-controller-0.4.7/tests/test_profile/test_special_actions.py
--- old/sc-controller-0.4.6.1/tests/test_profile/test_special_actions.py        
2018-12-21 00:20:53.000000000 +0100
+++ new/sc-controller-0.4.7/tests/test_profile/test_special_actions.py  
2019-07-08 14:28:01.000000000 +0200
@@ -161,3 +161,11 @@
                assert isinstance(a, OSDAction)
                assert isinstance(a.action, GesturesAction)
                assert isinstance(a.action.gestures['UD'], TurnOffAction)
+       
+       
+       def test_cemuhook(self):
+               """
+               Nothing to test here
+               """
+               pass
+


Reply via email to