[3/3] joy.cpl: Disable joysticks on Linux using joy.cpl

Lucas Zawacki lfzawacki at gmail.com
Mon Aug 20 01:47:06 CDT 2012


From: Lucas Zawacki <lfzawacki at gmail.com>

This uses the Wine defined GUIDs for joysticks to identify them and disable
the desired drivers. This way users don't have to mess with the registry.

The registry read/write functions are based on the ones in Wine's dinput and are meant
to be reused to write more configurations as needed by joy.cpl.

---
 dlls/joy.cpl/joy.rc |    1 +
 dlls/joy.cpl/main.c |  257 ++++++++++++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 254 insertions(+), 4 deletions(-)

diff --git a/dlls/joy.cpl/joy.rc b/dlls/joy.cpl/joy.rc
index 0b07e15..c4a551d 100644
--- a/dlls/joy.cpl/joy.rc
+++ b/dlls/joy.cpl/joy.rc
@@ -39,6 +39,7 @@ FONT 8, "Ms Shell Dlg"
     LISTBOX         IDC_JOYSTICKLIST, 10, 20, 180, 70, WS_TABSTOP | WS_VSCROLL | LBS_NOTIFY
     LTEXT           "Disabled", IDC_STATIC, 10, 95, 100, 10
     LISTBOX         IDC_DISABLEDLIST, 10, 105, 180, 70, WS_TABSTOP | WS_VSCROLL | LBS_NOTIFY
+    LTEXT           "After disabling or enabling a device, the connected joysticks won't be updated here until you restart this applet.", IDC_STATIC, 10, 175, 200, 25
 }
 
 IDD_TEST DIALOG 0, 0, 320, 220
diff --git a/dlls/joy.cpl/main.c b/dlls/joy.cpl/main.c
index ab38638..6bdbfdb 100644
--- a/dlls/joy.cpl/main.c
+++ b/dlls/joy.cpl/main.c
@@ -32,6 +32,7 @@
 #include "ole2.h"
 
 #include "wine/debug.h"
+#include "wine/unicode.h"
 #include "joy.h"
 
 WINE_DEFAULT_DEBUG_CHANNEL(joycpl);
@@ -46,6 +47,8 @@ static const GUID linuxinput_guid = { 0x9e573eda, 0x7734, 0x11d2, {0x8d, 0x4a, 0
 static REFGUID wine_guids[] = { &linux_guid, &linuxinput_guid };
 
 static const WCHAR wine_device_names[2][9] = { {' ','(','j','s',')','\0'}, {' ','(','e','v','e','n','t',')','\0'} };
+static const WCHAR wine_drv_names[2][11] = { {'j','s','\0'}, {'e','v','e','n','t','\0'} };
+static const WCHAR driver_delim[] = {',','\0'};
 
 /*********************************************************************
  *  DllMain
@@ -187,6 +190,217 @@ static void initialize_joysticks_list(HWND hwnd, struct JoystickData *data)
     }
 }
 
+/******************************************************************************
+ * get_app_key [internal]
+ * Get the default DirectInput key and the selected app config key.
+ */
+static BOOL get_app_key(HKEY *defkey, HKEY *appkey)
+{
+    static const WCHAR reg_key[] = { 'S','o','f','t','w','a','r','e','\\',
+                                     'W','i','n','e','\\',
+                                     'D','i','r','e','c','t','I','n','p','u','t','\0' };
+    *appkey = 0;
+
+    /* Registry key can be found in HKCU\Software\Wine\DirectInput */
+    if (RegCreateKeyExW(HKEY_CURRENT_USER, reg_key, 0, NULL, 0, KEY_SET_VALUE | KEY_READ, NULL, defkey, NULL))
+        *defkey = 0;
+
+    return *defkey || *appkey;
+}
+
+/******************************************************************************
+ * get_config_key [internal]
+ * Get a config key from either the app-specific or the default config
+ */
+DWORD get_config_key(HKEY defkey, HKEY appkey, const WCHAR *name, WCHAR *buffer, DWORD size)
+{
+    if (appkey && !RegQueryValueExW(appkey, name, 0, NULL, (LPBYTE)buffer, &size))
+        return 0;
+
+    if (defkey && !RegQueryValueExW(defkey, name, 0, NULL, (LPBYTE)buffer, &size))
+        return 0;
+
+    return ERROR_FILE_NOT_FOUND;
+}
+
+/******************************************************************************
+ * set_config_key [internal]
+ * Writes a string value to a registry key, deletes the key if value == NULL
+ */
+static DWORD set_config_key(HKEY defkey, HKEY appkey, const WCHAR *name, const WCHAR *value, DWORD size)
+{
+    if (value == NULL)
+    {
+        if (appkey && !RegDeleteValueW(appkey, name))
+            return 0;
+
+        if (defkey && !RegDeleteValueW(defkey, name))
+            return 0;
+    }
+    else
+    {
+        if (appkey && !RegSetValueExW(appkey, name, 0, REG_SZ, (const BYTE*) value, (size + 1)*sizeof(WCHAR)))
+            return 0;
+
+        if (defkey && !RegSetValueExW(defkey, name, 0, REG_SZ, (const BYTE*) value, (size + 1)*sizeof(WCHAR)))
+            return 0;
+    }
+
+    return ERROR_FILE_NOT_FOUND;
+}
+
+/******************************************************************************
+ * enable_joystick [internal]
+ * Writes to the DirectInput registry key that enables/disables a joystick
+ * from being enumerated.
+ */
+static void enable_joystick(WCHAR *joy_name, REFGUID guid, BOOL enable)
+{
+    static const WCHAR disable_str[] = {'D','i','s','a','b','l','e',' ','\0'};
+    WCHAR *disable_name;
+    const WCHAR *drv = NULL;
+    HKEY hkey, appkey;
+    int i;
+    int name_size = lstrlenW(disable_str) + lstrlenW(joy_name) + 1;
+
+    disable_name = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, name_size * sizeof(WCHAR));
+    lstrcatW(disable_name, disable_str);
+    lstrcatW(disable_name, joy_name);
+
+    get_app_key(&hkey, &appkey);
+
+    if (!enable)
+    {
+        /* Discover linux joystick driver based on GUID */
+        for (i=0; i < sizeof(wine_guids)/sizeof(wine_guids[0]); i++)
+            if (IsEqualGUID(wine_guids[i], guid))
+                drv = wine_drv_names[i];
+
+        if (drv)
+        {
+            /* Before setting test to see if we already have a driver disabled */
+            WCHAR buffer[MAX_PATH];
+            HRESULT hr;
+
+            hr = get_config_key(hkey, appkey, disable_name, buffer, sizeof(buffer));
+
+            /* If we have one already, just add the new one to the end */
+            if (hr != ERROR_FILE_NOT_FOUND)
+                lstrcatW(buffer, driver_delim);
+            else
+                buffer[0] = '\0';
+
+            lstrcatW(buffer, drv);
+
+            set_config_key(hkey, appkey, disable_name, buffer, lstrlenW(buffer));
+        }
+        else
+            WARN("Joysticks can only be disabled on Linux\n");
+    }
+    else
+        set_config_key(hkey, appkey, disable_name, NULL, 0);
+
+    HeapFree(GetProcessHeap(), 0, disable_name);
+    if (hkey) RegCloseKey(hkey);
+    if (appkey) RegCloseKey(appkey);
+}
+
+static void insert_disabled_joystick(HWND hwnd, WCHAR *name, WCHAR *driver, int n)
+{
+    WCHAR name_buffer[MAX_PATH];
+    const WCHAR *drv = NULL;
+    int i;
+
+    for (i=0; i < sizeof(wine_drv_names)/sizeof(wine_drv_names[0]); i++)
+    {
+        if (!lstrcmpW(driver, wine_drv_names[i]))
+            drv = wine_device_names[i];
+    }
+
+    name_buffer[0] = '\0';
+    lstrcatW(name_buffer, name);
+
+    if (drv == NULL)
+    {
+        WARN("Won't disable joystick '%s' with invalid driver name '%s'\n", debugstr_w(name), debugstr_w(driver));
+        return;
+    }
+
+    lstrcatW(name_buffer, drv);
+
+    /* Insert "device_name (driver)" in the list, but store the size of device_name in the
+       data field. This way we're able to get it back when needed.
+    */
+    SendDlgItemMessageW(hwnd, IDC_DISABLEDLIST, LB_ADDSTRING, 0, (LPARAM) name_buffer);
+    SendDlgItemMessageW(hwnd, IDC_DISABLEDLIST, LB_SETITEMDATA, n, (LPARAM) lstrlenW(name));
+}
+
+static void initialize_disabled_joysticks_list(HWND hwnd)
+{
+    static const WCHAR disable_str[] = {'D','i','s','a','b','l','e',' ','\0'};
+    HKEY hkey, appkey;
+    DWORD values = 0;
+    HRESULT hr;
+    int i, added = 0;
+
+    SendDlgItemMessageW(hwnd, IDC_DISABLEDLIST, LB_RESETCONTENT, 0, 0);
+
+    /* Search for disabled joysticks */
+    get_app_key(&hkey, &appkey);
+
+    RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, &values, NULL, NULL, NULL, NULL);
+
+    for (i=0; i < values; i++)
+    {
+        DWORD name_len = MAX_PATH, data_len = MAX_PATH;
+        WCHAR buf_name[MAX_PATH + 9], buf_data[MAX_PATH];
+
+        /* Pointer to the start of the name, without "Disabled" */
+        WCHAR *name = buf_name + lstrlenW(disable_str);
+
+        /* List all values under DirectInput and look for disabled joysticks */
+        hr = RegEnumValueW(hkey, i, buf_name, &name_len, NULL, NULL, (BYTE*) buf_data, &data_len);
+
+        if (SUCCEEDED(hr))
+        {
+            WCHAR *ptr_start, *ptr_end;
+
+            /* Ignore if key does not start with "Disable" */
+            if(strncmpW(disable_str, buf_name, lstrlenW(disable_str)))
+                continue;
+
+            /* Test if more than one driver is disabled for this joystick */
+            if ((ptr_end = strstrW(buf_data, driver_delim)) != NULL)
+            {
+                ptr_end[0] = '\0';
+
+                /* The first one */
+                insert_disabled_joystick(hwnd, name, buf_data, added);
+
+                /* Look at the rest */
+                while (ptr_end != NULL)
+                {
+                    added += 1;
+                    ptr_start = ptr_end + 1;
+                    ptr_end = strstrW(ptr_start, driver_delim);
+
+                    if (ptr_end != NULL)
+                        ptr_end[0] = '\0';
+
+                    insert_disabled_joystick(hwnd, name, ptr_start, added);
+                }
+            }
+            else
+                insert_disabled_joystick(hwnd, name, buf_data, added);
+
+            added += 1;
+
+        }
+    }
+
+    if (hkey) RegCloseKey(hkey);
+    if (appkey) RegCloseKey(appkey);
+}
 
 /*********************************************************************
  * list_dlgproc [internal]
@@ -203,6 +417,10 @@ static INT_PTR CALLBACK list_dlgproc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM
             data = (struct JoystickData*) ((PROPSHEETPAGEW*)lparam)->lParam;
 
             initialize_joysticks_list(hwnd, data);
+            initialize_disabled_joysticks_list(hwnd);
+
+            EnableWindow(GetDlgItem(hwnd, IDC_BUTTONENABLE), FALSE);
+            EnableWindow(GetDlgItem(hwnd, IDC_BUTTONDISABLE), FALSE);
 
             /* Store the hwnd to be used with MapDialogRect for unit conversions */
             data->graphics.hwnd = hwnd;
@@ -215,12 +433,43 @@ static INT_PTR CALLBACK list_dlgproc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM
             switch (LOWORD(wparam))
             {
                 case IDC_BUTTONDISABLE:
-                    FIXME("Disable selected joystick from being enumerated\n");
-                    break;
+                {
+                    int sel = SendDlgItemMessageW(hwnd, IDC_JOYSTICKLIST, LB_GETCURSEL, 0, 0);
+
+                    if (sel >= 0)
+                    {
+                        enable_joystick(data->joysticks[sel].instance.tszInstanceName,
+                                        &data->joysticks[sel].instance.guidProduct, FALSE);
+                        initialize_disabled_joysticks_list(hwnd);
+                    }
+                }
+                break;
 
                 case IDC_BUTTONENABLE:
-                    FIXME("Re-Enable selected joystick\n");
-                    break;
+                {
+                    int sel = SendDlgItemMessageW(hwnd, IDC_DISABLEDLIST, LB_GETCURSEL, 0, 0);
+
+                    if (sel >= 0)
+                    {
+                        WCHAR text[MAX_PATH];
+                        int text_size = SendDlgItemMessageW(hwnd, IDC_DISABLEDLIST, LB_GETITEMDATA, sel, 0);
+                        SendDlgItemMessageW(hwnd, IDC_DISABLEDLIST, LB_GETTEXT, sel, (LPARAM) text);
+
+                        text[text_size] = '\0';
+                        enable_joystick(text, NULL, TRUE);
+                        initialize_disabled_joysticks_list(hwnd);
+                    }
+                }
+
+                case IDC_JOYSTICKLIST:
+                    EnableWindow(GetDlgItem(hwnd, IDC_BUTTONENABLE), FALSE);
+                    EnableWindow(GetDlgItem(hwnd, IDC_BUTTONDISABLE), TRUE);
+                break;
+
+                case IDC_DISABLEDLIST:
+                    EnableWindow(GetDlgItem(hwnd, IDC_BUTTONENABLE), TRUE);
+                    EnableWindow(GetDlgItem(hwnd, IDC_BUTTONDISABLE), FALSE);
+                break;
             }
             return TRUE;
 
-- 
1.7.9.5




More information about the wine-patches mailing list