[OSK] Implement "Use Click Sound" feature
[reactos.git] / base / applications / osk / main.c
index 9932f79..972f8c8 100644 (file)
@@ -9,6 +9,7 @@
 /* INCLUDES *******************************************************************/
 
 #include "osk.h"
+#include "settings.h"
 
 /* GLOBALS ********************************************************************/
 
@@ -23,7 +24,7 @@ BOOL OSK_DlgCommand(WPARAM wCommand, HWND hWndControl);
 BOOL OSK_ReleaseKey(WORD ScanCode);
 
 INT_PTR APIENTRY OSK_DlgProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam);
-int WINAPI _tWinMain(HINSTANCE, HINSTANCE, LPTSTR, int);
+int WINAPI wWinMain(HINSTANCE, HINSTANCE, LPWSTR, int);
 
 /* FUNCTIONS ******************************************************************/
 
@@ -38,8 +39,8 @@ int OSK_SetImage(int IdDlgItem, int IdResource)
     HICON hIcon;
     HWND hWndItem;
 
-    hIcon = (HICON)LoadImage(Globals.hInstance, MAKEINTRESOURCE(IdResource),
-                             IMAGE_ICON, 16, 16, LR_DEFAULTCOLOR);
+    hIcon = (HICON)LoadImageW(Globals.hInstance, MAKEINTRESOURCEW(IdResource),
+                              IMAGE_ICON, 16, 16, LR_DEFAULTCOLOR);
     if (hIcon == NULL)
         return FALSE;
 
@@ -50,13 +51,80 @@ int OSK_SetImage(int IdDlgItem, int IdResource)
         return FALSE;
     }
 
-    SendMessage(hWndItem, BM_SETIMAGE, (WPARAM)IMAGE_ICON, (LPARAM)hIcon);
+    SendMessageW(hWndItem, BM_SETIMAGE, (WPARAM)IMAGE_ICON, (LPARAM)hIcon);
 
     /* The system automatically deletes these resources when the process that created them terminates (MSDN) */
 
     return TRUE;
 }
 
+/***********************************************************************
+ *
+ *          OSK_WarningProc
+ *
+ *  Function handler for the warning dialog box on startup
+ */
+INT_PTR CALLBACK OSK_WarningProc(HWND hDlg, UINT Msg, WPARAM wParam, LPARAM lParam)
+{
+    UNREFERENCED_PARAMETER(lParam);
+
+    switch (Msg)
+    {
+        case WM_INITDIALOG:
+        {
+            return TRUE;
+        }
+
+        case WM_COMMAND:
+        {
+            switch (LOWORD(wParam))
+            {
+                case IDC_SHOWWARNINGCHECK:
+                {
+                    Globals.bShowWarning = !IsDlgButtonChecked(hDlg, IDC_SHOWWARNINGCHECK);
+                    return TRUE;
+                }
+
+                case IDOK:
+                case IDCANCEL:
+                {
+                    EndDialog(hDlg, LOWORD(wParam));
+                    return TRUE;
+                }
+            }
+            break;
+        }
+    }
+
+    return FALSE;
+}
+
+/***********************************************************************
+ *
+ *          OSK_About
+ *
+ *  Initializes the "About" dialog box
+ */
+VOID OSK_About(VOID)
+{
+    WCHAR szTitle[MAX_BUFF];
+    WCHAR szAuthors[MAX_BUFF];
+    HICON OSKIcon;
+
+    /* Load the icon */
+    OSKIcon = LoadImageW(Globals.hInstance, MAKEINTRESOURCEW(IDI_OSK), IMAGE_ICON, 0, 0, LR_DEFAULTSIZE);
+
+    /* Load the strings into the "About" dialog */
+    LoadStringW(Globals.hInstance, STRING_OSK, szTitle, countof(szTitle));
+    LoadStringW(Globals.hInstance, STRING_AUTHORS, szAuthors, countof(szAuthors));
+
+    /* Finally, execute the "About" dialog by using the Shell routine */
+    ShellAboutW(Globals.hMainWnd, szTitle, szAuthors, OSKIcon);
+
+    /* Once done, destroy the icon */
+    DestroyIcon(OSKIcon);
+}
+
 
 /***********************************************************************
  *
@@ -66,7 +134,8 @@ int OSK_SetImage(int IdDlgItem, int IdResource)
  */
 int OSK_DlgInitDialog(HWND hDlg)
 {
-    HMONITOR  monitor;
+    HICON hIcon, hIconSm;
+    HMONITOR monitor;
     MONITORINFO info;
     POINT Pt;
     RECT rcWindow;
@@ -74,9 +143,39 @@ int OSK_DlgInitDialog(HWND hDlg)
     /* Save handle */
     Globals.hMainWnd = hDlg;
 
+    /* Check the checked menu item before displaying the modal box */
+    if (Globals.bIsEnhancedKeyboard)
+    {
+        /* Enhanced keyboard dialog chosen, set the respective menu item as checked */
+        CheckMenuItem(GetMenu(hDlg), IDM_ENHANCED_KB, MF_BYCOMMAND | MF_CHECKED);
+        CheckMenuItem(GetMenu(hDlg), IDM_STANDARD_KB, MF_BYCOMMAND | MF_UNCHECKED);
+    }
+    else
+    {
+        /* Standard keyboard dialog chosen, set the respective menu item as checked */
+        CheckMenuItem(GetMenu(hDlg), IDM_STANDARD_KB, MF_BYCOMMAND | MF_CHECKED);
+        CheckMenuItem(GetMenu(hDlg), IDM_ENHANCED_KB, MF_BYCOMMAND | MF_UNCHECKED);
+    }
+
+    /* Check if the "Click Sound" option was chosen before (and if so, then tick the menu item) */
+    if (Globals.bSoundClick)
+    {
+        CheckMenuItem(GetMenu(hDlg), IDM_CLICK_SOUND, MF_BYCOMMAND | MF_CHECKED);
+    }
+
+    /* Set the application's icon */
+    hIcon = LoadImageW(Globals.hInstance, MAKEINTRESOURCEW(IDI_OSK), IMAGE_ICON, 0, 0, LR_SHARED | LR_DEFAULTSIZE);
+    hIconSm = CopyImage(hIcon, IMAGE_ICON, GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), LR_COPYFROMRESOURCE);
+    if (hIcon || hIconSm)
+    {
+        /* Set the window icons (they are deleted when the process terminates) */
+        SendMessageW(Globals.hMainWnd, WM_SETICON, ICON_BIG, (LPARAM)hIcon);
+        SendMessageW(Globals.hMainWnd, WM_SETICON, ICON_SMALL, (LPARAM)hIconSm);
+    }
+
     /* Get screen info */
     memset(&Pt, 0, sizeof(Pt));
-    monitor = MonitorFromPoint(Pt, MONITOR_DEFAULTTOPRIMARY );
+    monitor = MonitorFromPoint(Pt, MONITOR_DEFAULTTOPRIMARY);
     info.cbSize = sizeof(info);
     GetMonitorInfoW(monitor, &info);
 
@@ -139,6 +238,9 @@ int OSK_DlgClose(void)
     /* delete GDI objects */
     if (Globals.hBrushGreenLed) DeleteObject(Globals.hBrushGreenLed);
 
+    /* Save the settings to the registry hive */
+    SaveDataToRegistry();
+
     return TRUE;
 }
 
@@ -188,19 +290,19 @@ BOOL OSK_DlgCommand(WPARAM wCommand, HWND hWndControl)
         MSG msg;
 
         SetForegroundWindow(Globals.hActiveWnd);
-        while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
+        while (PeekMessageW(&msg, 0, 0, 0, PM_REMOVE))
         {
             TranslateMessage(&msg);
-            DispatchMessage(&msg);
+            DispatchMessageW(&msg);
         }
     }
 
     /* KeyDown and/or KeyUp ? */
-    WindowStyle = GetWindowLong(hWndControl, GWL_STYLE);
+    WindowStyle = GetWindowLongW(hWndControl, GWL_STYLE);
     if ((WindowStyle & BS_AUTOCHECKBOX) == BS_AUTOCHECKBOX)
     {
         /* 2-states key like Shift, Alt, Ctrl, ... */
-        if (SendMessage(hWndControl, BM_GETCHECK, 0, 0) == BST_CHECKED)
+        if (SendMessageW(hWndControl, BM_GETCHECK, 0, 0) == BST_CHECKED)
         {
             bKeyDown = TRUE;
             bKeyUp = FALSE;
@@ -251,6 +353,12 @@ BOOL OSK_DlgCommand(WPARAM wCommand, HWND hWndControl)
         SendInput(1, &Input, sizeof(Input));
     }
 
+    /* Play the sound during clicking event (only if "Use Click Sound" menu option is ticked) */
+    if (Globals.bSoundClick)
+    {
+        PlaySoundW(MAKEINTRESOURCEW(IDI_SOUNDCLICK), GetModuleHandle(NULL), SND_RESOURCE | SND_ASYNC);
+    }
+
     return TRUE;
 }
 
@@ -269,11 +377,11 @@ BOOL OSK_ReleaseKey(WORD ScanCode)
 
     /* Is it a 2-states key ? */
     hWndControl = GetDlgItem(Globals.hMainWnd, ScanCode);
-    WindowStyle = GetWindowLong(hWndControl, GWL_STYLE);
+    WindowStyle = GetWindowLongW(hWndControl, GWL_STYLE);
     if ((WindowStyle & BS_AUTOCHECKBOX) != BS_AUTOCHECKBOX) return FALSE;
 
     /* Is the key down ? */
-    if (SendMessage(hWndControl, BM_GETCHECK, 0, 0) != BST_CHECKED) return TRUE;
+    if (SendMessageW(hWndControl, BM_GETCHECK, 0, 0) != BST_CHECKED) return TRUE;
 
     /* Extended key ? */
     if (ScanCode & 0x0200)
@@ -336,10 +444,102 @@ INT_PTR APIENTRY OSK_DlgProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
             break;
 
         case WM_COMMAND:
-            if (wParam == IDCANCEL)
-                EndDialog(hDlg, FALSE);
-            else if (wParam != IDC_STATIC)
-                OSK_DlgCommand(wParam, (HWND) lParam);
+            switch (LOWORD(wParam))
+            {
+                case IDCANCEL:
+                {
+                    EndDialog(hDlg, FALSE);
+                    break;
+                }
+
+                case IDM_EXIT:
+                {
+                    EndDialog(hDlg, FALSE);
+                    break;
+                }
+
+                case IDM_ENHANCED_KB:
+                {
+                    if (!Globals.bIsEnhancedKeyboard)
+                    {
+                        /* 
+                            The user attempted to switch to enhanced keyboard dialog type.
+                            Set the member value as TRUE, destroy the dialog and save the data configuration into the registry.
+                        */
+                        Globals.bIsEnhancedKeyboard = TRUE;
+                        EndDialog(hDlg, FALSE);
+                        SaveDataToRegistry();
+
+                        /* Change the condition of enhanced keyboard item menu to checked */
+                        CheckMenuItem(GetMenu(hDlg), IDM_ENHANCED_KB, MF_BYCOMMAND | MF_CHECKED);
+                        CheckMenuItem(GetMenu(hDlg), IDM_STANDARD_KB, MF_BYCOMMAND | MF_UNCHECKED);
+
+                        /* Finally, display the dialog modal box with the enhanced keyboard dialog */
+                        DialogBoxW(Globals.hInstance,
+                                   MAKEINTRESOURCEW(MAIN_DIALOG_ENHANCED_KB),
+                                   GetDesktopWindow(),
+                                   OSK_DlgProc);
+                    }
+
+                    break;
+                }
+
+                case IDM_STANDARD_KB:
+                {
+                    if (Globals.bIsEnhancedKeyboard)
+                    {
+                        /*
+                            The user attempted to switch to standard keyboard dialog type.
+                            Set the member value as FALSE, destroy the dialog and save the data configuration into the registry.
+                        */
+                        Globals.bIsEnhancedKeyboard = FALSE;
+                        EndDialog(hDlg, FALSE);
+                        SaveDataToRegistry();
+
+                        /* Change the condition of standard keyboard item menu to checked */
+                        CheckMenuItem(GetMenu(hDlg), IDM_ENHANCED_KB, MF_BYCOMMAND | MF_UNCHECKED);
+                        CheckMenuItem(GetMenu(hDlg), IDM_STANDARD_KB, MF_BYCOMMAND | MF_CHECKED);
+
+                        /* Finally, display the dialog modal box with the standard keyboard dialog */
+                        DialogBoxW(Globals.hInstance,
+                                   MAKEINTRESOURCEW(MAIN_DIALOG_STANDARD_KB),
+                                   GetDesktopWindow(),
+                                   OSK_DlgProc);
+                    }
+
+                    break;
+                }
+
+                case IDM_CLICK_SOUND:
+                {
+                    /*
+                        This case is triggered when the user attempts to click on the menu item. Before doing anything,
+                        we must check the condition state of such menu item so that we can tick/untick the menu item accordingly.
+                    */
+                    if (!Globals.bSoundClick)
+                    {
+                        Globals.bSoundClick = TRUE;
+                        CheckMenuItem(GetMenu(hDlg), IDM_CLICK_SOUND, MF_BYCOMMAND | MF_CHECKED);
+                    }
+                    else
+                    {
+                        Globals.bSoundClick = FALSE;
+                        CheckMenuItem(GetMenu(hDlg), IDM_CLICK_SOUND, MF_BYCOMMAND | MF_UNCHECKED);
+                    }
+
+                    break;
+                }
+
+                case IDM_ABOUT:
+                {
+                    OSK_About();
+                    break;
+                }
+
+                default:
+                    OSK_DlgCommand(wParam, (HWND)lParam);
+                    break;
+            }
             break;
 
         case WM_CLOSE:
@@ -354,12 +554,13 @@ INT_PTR APIENTRY OSK_DlgProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
  *
  *       WinMain
  */
-int WINAPI _tWinMain(HINSTANCE hInstance,
-                     HINSTANCE prev,
-                     LPTSTR cmdline,
-                     int show)
+int WINAPI wWinMain(HINSTANCE hInstance,
+                    HINSTANCE prev,
+                    LPWSTR cmdline,
+                    int show)
 {
     HANDLE hMutex;
+    INT LayoutResource;
 
     UNREFERENCED_PARAMETER(prev);
     UNREFERENCED_PARAMETER(cmdline);
@@ -368,18 +569,38 @@ int WINAPI _tWinMain(HINSTANCE hInstance,
     ZeroMemory(&Globals, sizeof(Globals));
     Globals.hInstance = hInstance;
 
+    /* Load the settings from the registry hive */
+    LoadDataFromRegistry();
+
+    /* If the member of the struct (bShowWarning) is set then display the dialog box */
+    if (Globals.bShowWarning)
+    {
+        DialogBoxW(Globals.hInstance, MAKEINTRESOURCEW(IDD_WARNINGDIALOG_OSK), Globals.hMainWnd, OSK_WarningProc);
+    }
+
+    /* Before initializing the dialog execution, check if the chosen keyboard type is standard or enhanced */
+    if (Globals.bIsEnhancedKeyboard)
+    {
+        LayoutResource = MAIN_DIALOG_ENHANCED_KB;
+    }
+    else
+    {
+        LayoutResource = MAIN_DIALOG_STANDARD_KB;
+    }
+
     /* Rry to open a mutex for a single instance */
-    hMutex = OpenMutexA(MUTEX_ALL_ACCESS, FALSE, "osk");
+    hMutex = OpenMutexW(MUTEX_ALL_ACCESS, FALSE, L"osk");
 
     if (!hMutex)
     {
         /* Mutex doesn\92t exist. This is the first instance so create the mutex. */
-        hMutex = CreateMutexA(NULL, FALSE, "osk");
+        hMutex = CreateMutexW(NULL, FALSE, L"osk");
 
-        DialogBox(hInstance,
-                  MAKEINTRESOURCE(MAIN_DIALOG),
-                  GetDesktopWindow(),
-                  OSK_DlgProc);
+        /* Create the modal box based on the configuration registry */
+        DialogBoxW(hInstance,
+                   MAKEINTRESOURCEW(LayoutResource),
+                   GetDesktopWindow(),
+                   OSK_DlgProc);
 
         /* Delete the mutex */
         if (hMutex) CloseHandle(hMutex);