From a729e33cfb20134ad278ce9a33f609da10ff314a Mon Sep 17 00:00:00 2001 From: crs Date: Mon, 2 Sep 2002 17:30:04 +0000 Subject: [PATCH] Fixed win32 config saving, keyboard mapping, and AltGr bugs. Made extensive changes to the launcher to provide more control over setting up auto-start and it now saves configuration to the user's documents directory if auto-starting at login and saves to the system directory if auto-starting at boot. Replaced MapVirtualKey() with table lookup to work around that function's lack of support for extended keyboard scan codes. Added first cut at support for AltGr. --- BUGS | 10 +- INSTALL | 48 +- cmd/launcher/CAutoStart.cpp | 262 ++++++++++ cmd/launcher/CAutoStart.h | 81 +++ cmd/launcher/LaunchUtil.cpp | 211 ++++++++ cmd/launcher/LaunchUtil.h | 50 ++ cmd/launcher/launcher.cpp | 366 ++++--------- cmd/launcher/launcher.dsp | 16 + cmd/launcher/launcher.rc | 95 +++- cmd/launcher/resource.h | 147 +++--- cmd/synergyc/resource.h | 38 +- cmd/synergyc/synergyc.cpp | 171 +----- cmd/synergyc/synergyc.rc | 11 - cmd/synergys/resource.h | 38 +- cmd/synergys/synergys.cpp | 122 +---- lib/client/CClient.cpp | 4 +- lib/client/CMSWindowsSecondaryScreen.cpp | 6 + lib/platform/CUnixPlatform.cpp | 17 +- lib/platform/CUnixPlatform.h | 9 +- lib/platform/CWin32Platform.cpp | 135 ++++- lib/platform/CWin32Platform.h | 10 +- lib/platform/IPlatform.h | 28 +- lib/server/CMSWindowsPrimaryScreen.cpp | 632 +++++++++++------------ 23 files changed, 1455 insertions(+), 1052 deletions(-) create mode 100755 cmd/launcher/CAutoStart.cpp create mode 100755 cmd/launcher/CAutoStart.h create mode 100755 cmd/launcher/LaunchUtil.cpp create mode 100755 cmd/launcher/LaunchUtil.h diff --git a/BUGS b/BUGS index e429fda7..854f27e8 100644 --- a/BUGS +++ b/BUGS @@ -1,7 +1,8 @@ Known Bugs in Synergy ===================== -Report bugs to: synergy@groundhog.pair.com +Report bugs at: +http://sourceforge.net/tracker/?func=browse&group_id=59275&atid=490467 When reporting bugs, please include the version of the operating system you're using and what locale you use. @@ -77,10 +78,9 @@ system you're using and what locale you use. when toggled on and KeyRelease when toggled off (instead of KeyPress and KeyRelease for each physical press and release). -* Not handling mode-switch and shift-lock (X11) +* Not handling shift-lock (X11) - Synergy neither handles the mode-switch key nor shift-lock behavior - (as opposed to caps-lock). + Synergy doesn't handle shift-lock behavior (as opposed to caps-lock). * Large Motif clipboard items are truncated (X11) @@ -94,4 +94,4 @@ system you're using and what locale you use. * Automake isn't fully configured (Linux) The automake configuration isn't complete so synergy won't build - properly on some (many) systems. + or fail to build properly on some (many) systems. diff --git a/INSTALL b/INSTALL index d5a49793..40b1355a 100644 --- a/INSTALL +++ b/INSTALL @@ -96,9 +96,9 @@ First configure the server. Click the `Server' radio button * Click `Test' The server will start and you'll see a console window with log messages -telling you about synergy's progress. If an error occurs you'll get a -dialog box telling you synergy is about to quit; read the log messages -to determine the problem then correct it and try `Test' again. +telling you about synergy's progress. If an error occurs you'll get one +or more dialog boxes telling you what the errors are; read the errors +to determine the problem then correct them and try `Test' again. Now that the server is running, you'll need to start a client. On any client computer, double click `synergy'. Of course, you'll need to @@ -115,9 +115,9 @@ client computer. Then configure the client: * Click `Test' If all goes well, the client connects to the server successfully and -the mouse and keyboard are shared. If an error occurs you'll get a -dialog box telling you synergy is about to quit; read the log messages -to determine the problem then correct it and try `Test' again. When +the mouse and keyboard are shared. If an error occurs you'll get one +or more dialog boxes telling you what the errors are; read the errors +to determine the problem then correct them and try `Test' again. When everything is working correctly, install the software on the other client computers (if any) and repeat the steps for configuring the client on each. @@ -289,17 +289,31 @@ Starting Automatically on Windows When all the clients work you're ready to have synergy start automatically each time the system (re)starts. Click `Stop' on all -the clients then on the server'. Then Click `Start' on the server. -If it starts successfully then click `OK' to close the message box -and the dialog. The synergy server is now running and will be -automatically started each time the system is started. Click `Start' -then `OK' on each of the clients to start the synergy client and -automatically have it start each time the computer starts. +the clients then on the server'. Now click the `Configure' button by +the text `Automatic Startup'. The `Auto Start' dialog will pop up. +If an error occurs then correct the problem and click `Configure' +again. -If you ever want to prevent synergy from starting automatically when -the computer does, double click `synergy', choose `Client' or `Server' -(whichever the computer is running as), then click `No Auto-Start'. -Click `OK' to dismiss the message box then `Quit' to close the dialog. +On the `Auto Start' dialog you'll configure synergy to start +automatically when the computer starts or when you log in. You can +also configure synergy to not start automatically. You can only +start synergy automatically when the computer starts if you have +sufficient access rights. The dialog will let you know if you have +sufficient permission. + +If synergy is already configured to automatically start then there +will be two `Uninstall' buttons, at most one of which is enabled. +Click the enabled button, if any, to configure synergy to not start +automatically. + +If synergy is not configured to start automatically then there will +be two `Install' buttons. If you have sufficient permission to +have synergy start automatically when the computer does then the +`Install' button in the `When Computer Starts' box will be enabled. +Click it to have synergy start for all users when the computer starts. +In this case, synergy will be available during the login screen. +Otherwise, click the `Install' button in the `When You Log In' box +to have synergy automatically start when you log in. Starting Automatically on Linux @@ -353,8 +367,6 @@ Common Command Line Options -1, --no-restart do not restart on failure -h, --help print help and exit --version print version information and exit - --install install as a service (Windows only) - --uninstall uninstall service (Windows only) Debug levels are from highest to lowest: FATAL, ERROR, WARNING, NOTE, INFO, DEBUG, DEBUG1, and DEBUG2. Only messages at or above the given diff --git a/cmd/launcher/CAutoStart.cpp b/cmd/launcher/CAutoStart.cpp new file mode 100755 index 00000000..f13345e7 --- /dev/null +++ b/cmd/launcher/CAutoStart.cpp @@ -0,0 +1,262 @@ +/* + * synergy -- mouse and keyboard sharing utility + * Copyright (C) 2002 Chris Schoeneman + * + * This package is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * found in the file COPYING that should have accompanied this file. + * + * This package is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include "CPlatform.h" +#include "CLog.h" +#include "CAutoStart.h" +#include "LaunchUtil.h" +#include "resource.h" + +#define CLIENT_DAEMON_NAME "Synergy Client" +#define SERVER_DAEMON_NAME "Synergy Server" +#define CLIENT_DAEMON_INFO "Shares this system's mouse and keyboard with others." +#define SERVER_DAEMON_INFO "Shares this system's mouse and keyboard with others." + +// +// CAutoStart +// + +CAutoStart* CAutoStart::s_singleton = NULL; + +CAutoStart::CAutoStart(HWND parent, CConfig* config, const CString& cmdLine) : + m_parent(parent), + m_config(config), + m_isServer(config != NULL), + m_cmdLine(cmdLine), + m_name((config != NULL) ? SERVER_DAEMON_NAME : CLIENT_DAEMON_NAME), + m_userConfigSaved(false) + +{ + assert(s_singleton == NULL); + s_singleton = this; +} + +CAutoStart::~CAutoStart() +{ + s_singleton = NULL; +} + +void +CAutoStart::doModal() +{ + // install our log outputter + CLog::Outputter oldOutputter = CLog::getOutputter(); + CLog::setOutputter(&CAutoStart::onLog); + + // reset saved flag + m_userConfigSaved = false; + + // do dialog + DialogBoxParam(s_instance, MAKEINTRESOURCE(IDD_AUTOSTART), + m_parent, dlgProc, (LPARAM)this); + + // restore log outputter + CLog::setOutputter(oldOutputter); +} + +bool +CAutoStart::wasUserConfigSaved() const +{ + return m_userConfigSaved; +} + +void +CAutoStart::update() +{ + // need a platform object + CPlatform platform; + + // get installation state + const bool installedSystem = platform.isDaemonInstalled( + m_name.c_str(), true); + const bool installedUser = platform.isDaemonInstalled( + m_name.c_str(), false); + + // get user's permissions + const bool canInstallSystem = platform.canInstallDaemon( + m_name.c_str(), true); + const bool canInstallUser = platform.canInstallDaemon( + m_name.c_str(), false); + + // update messages + CString msg, label; + if (canInstallSystem) { + msg = getString(IDS_AUTOSTART_PERMISSION_SYSTEM); + } + else if (canInstallUser) { + msg = getString(IDS_AUTOSTART_PERMISSION_USER); + } + else { + msg = getString(IDS_AUTOSTART_PERMISSION_NONE); + } + setWindowText(getItem(m_hwnd, IDC_AUTOSTART_PERMISSION_MSG), msg); + if (installedSystem) { + msg = getString(IDS_AUTOSTART_INSTALLED_SYSTEM); + label = getString(IDS_UNINSTALL_LABEL); + } + else if (installedUser) { + msg = getString(IDS_AUTOSTART_INSTALLED_USER); + label = getString(IDS_UNINSTALL_LABEL); + } + else { + msg = getString(IDS_AUTOSTART_INSTALLED_NONE); + label = getString(IDS_INSTALL_LABEL); + } + setWindowText(getItem(m_hwnd, IDC_AUTOSTART_INSTALLED_MSG), msg); + + // update buttons + setWindowText(getItem(m_hwnd, IDC_AUTOSTART_INSTALL_SYSTEM), label); + setWindowText(getItem(m_hwnd, IDC_AUTOSTART_INSTALL_USER), label); + if (installedSystem) { + enableItem(m_hwnd, IDC_AUTOSTART_INSTALL_SYSTEM, canInstallSystem); + enableItem(m_hwnd, IDC_AUTOSTART_INSTALL_USER, false); + m_install = false; + } + else if (installedUser) { + enableItem(m_hwnd, IDC_AUTOSTART_INSTALL_SYSTEM, false); + enableItem(m_hwnd, IDC_AUTOSTART_INSTALL_USER, canInstallUser); + m_install = false; + } + else { + enableItem(m_hwnd, IDC_AUTOSTART_INSTALL_SYSTEM, canInstallSystem); + enableItem(m_hwnd, IDC_AUTOSTART_INSTALL_USER, canInstallUser); + m_install = true; + } +} + +bool +CAutoStart::onInstall(bool allUsers) +{ + if (!m_install) { + return onUninstall(allUsers); + } + + // try saving configuration. if we can't then don't try + // installing the daemon. + if (m_config != NULL) { + if (!saveConfig(*m_config, allUsers)) { + showError(m_hwnd, CStringUtil::format( + getString(IDS_SAVE_FAILED).c_str(), + getErrorString(GetLastError()).c_str())); + return false; + } + + // note if we've saved the user's configuration + if (!allUsers) { + m_userConfigSaved = true; + } + } + + // get the app path + CString appPath = getAppPath(m_isServer ? SERVER_APP : CLIENT_APP); + + // clear error message + m_errorMessage = ""; + + // install + CPlatform platform; + if (!platform.installDaemon(m_name.c_str(), + m_isServer ? SERVER_DAEMON_INFO : CLIENT_DAEMON_INFO, + appPath.c_str(), m_cmdLine.c_str(), allUsers)) { + if (m_errorMessage.empty()) { + m_errorMessage = getString(IDS_INSTALL_GENERIC_ERROR); + } + showError(m_hwnd, m_errorMessage); + return false; + } + + askOkay(m_hwnd, getString(IDS_INSTALL_TITLE), + getString(allUsers ? + IDS_INSTALLED_SYSTEM : + IDS_INSTALLED_USER)); + return true; +} + +bool +CAutoStart::onUninstall(bool allUsers) +{ + // clear error message + m_errorMessage = ""; + + // uninstall + CPlatform platform; + if (platform.uninstallDaemon(m_name.c_str(), allUsers) != + IPlatform::kSuccess) { + if (m_errorMessage.empty()) { + m_errorMessage = getString(IDS_UNINSTALL_GENERIC_ERROR); + } + showError(m_hwnd, m_errorMessage); + return false; + } + + askOkay(m_hwnd, getString(IDS_UNINSTALL_TITLE), + getString(allUsers ? + IDS_UNINSTALLED_SYSTEM : + IDS_UNINSTALLED_USER)); + return true; +} + +bool +CAutoStart::onLog(int priority, const char* message) +{ + if (priority <= CLog::kERROR) { + s_singleton->m_errorMessage = message; + } + return true; +} + +BOOL +CAutoStart::doDlgProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM) +{ + switch (message) { + case WM_INITDIALOG: + // save our hwnd + m_hwnd = hwnd; + + // update the controls + update(); + + return TRUE; + + case WM_COMMAND: + switch (LOWORD(wParam)) { + case IDC_AUTOSTART_INSTALL_SYSTEM: + onInstall(true); + update(); + return TRUE; + + case IDC_AUTOSTART_INSTALL_USER: + onInstall(false); + update(); + return TRUE; + + case IDCANCEL: + EndDialog(hwnd, 0); + m_hwnd = NULL; + return TRUE; + } + break; + + default: + break; + } + + return FALSE; +} + +BOOL CALLBACK +CAutoStart::dlgProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) +{ + return s_singleton->doDlgProc(hwnd, message, wParam, lParam); +} diff --git a/cmd/launcher/CAutoStart.h b/cmd/launcher/CAutoStart.h new file mode 100755 index 00000000..954801ab --- /dev/null +++ b/cmd/launcher/CAutoStart.h @@ -0,0 +1,81 @@ +/* + * synergy -- mouse and keyboard sharing utility + * Copyright (C) 2002 Chris Schoeneman + * + * This package is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * found in the file COPYING that should have accompanied this file. + * + * This package is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef CAUTOSTART_H +#define CAUTOSTART_H + +#include "CString.h" + +#define WINDOWS_LEAN_AND_MEAN +#include + +class CConfig; + +//! Auto start dialog for Microsoft Windows launcher +class CAutoStart { +public: + // if config == NULL then it's assumed we're installing/uninstalling + // the client, otherwise the server. + CAutoStart(HWND parent, CConfig* config, const CString& cmdLine); + ~CAutoStart(); + + //! @name manipulators + //@{ + + //! Run dialog + /*! + Display and handle the dialog until closed by the user. + */ + void doModal(); + + //@} + //! @name accessors + //@{ + + //! Test if user configuration was saved + /*! + Returns true if the user's configuration (as opposed to the system-wide + configuration) was saved successfully while in doModal(). + */ + bool wasUserConfigSaved() const; + + //@} + +private: + void update(); + bool onInstall(bool allUsers); + bool onUninstall(bool allUsers); + + // log handling + static bool onLog(int priority, const char* message); + + // message handling + BOOL doDlgProc(HWND, UINT, WPARAM, LPARAM); + static BOOL CALLBACK dlgProc(HWND, UINT, WPARAM, LPARAM); + +private: + static CAutoStart* s_singleton; + + HWND m_parent; + CConfig* m_config; + bool m_isServer; + CString m_cmdLine; + CString m_name; + HWND m_hwnd; + bool m_install; + CString m_errorMessage; + bool m_userConfigSaved; +}; + +#endif diff --git a/cmd/launcher/LaunchUtil.cpp b/cmd/launcher/LaunchUtil.cpp new file mode 100755 index 00000000..57e31554 --- /dev/null +++ b/cmd/launcher/LaunchUtil.cpp @@ -0,0 +1,211 @@ +/* + * synergy -- mouse and keyboard sharing utility + * Copyright (C) 2002 Chris Schoeneman + * + * This package is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * found in the file COPYING that should have accompanied this file. + * + * This package is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include "CConfig.h" +#include "CPlatform.h" +#include "LaunchUtil.h" +#include "resource.h" +#include "stdfstream.h" + +#define CONFIG_NAME "synergy.sgc" + +CString +getString(DWORD id) +{ + char buffer[1024]; + buffer[0] = '\0'; + LoadString(s_instance, id, buffer, sizeof(buffer) / sizeof(buffer[0])); + return buffer; +} + +CString +getErrorString(DWORD error) +{ + char* buffer; + if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_IGNORE_INSERTS | + FORMAT_MESSAGE_FROM_SYSTEM, + 0, + error, + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + (LPTSTR)&buffer, + 0, + NULL) == 0) { + return getString(IDS_ERROR); + } + else { + CString result(buffer); + LocalFree(buffer); + return result; + } +} + +void +showError(HWND hwnd, const CString& msg) +{ + CString title = getString(IDS_ERROR); + MessageBox(hwnd, msg.c_str(), title.c_str(), MB_OK | MB_APPLMODAL); +} + +void +askOkay(HWND hwnd, const CString& title, const CString& msg) +{ + MessageBox(hwnd, msg.c_str(), title.c_str(), MB_OK | MB_APPLMODAL); +} + +bool +askVerify(HWND hwnd, const CString& msg) +{ + CString title = getString(IDS_VERIFY); + int result = MessageBox(hwnd, msg.c_str(), + title.c_str(), MB_OKCANCEL | MB_APPLMODAL); + return (result == IDOK); +} + +void +setWindowText(HWND hwnd, const CString& msg) +{ + SendMessage(hwnd, WM_SETTEXT, 0, (LPARAM)msg.c_str()); +} + +CString +getWindowText(HWND hwnd) +{ + LRESULT size = SendMessage(hwnd, WM_GETTEXTLENGTH, 0, 0); + char* buffer = new char[size + 1]; + SendMessage(hwnd, WM_GETTEXT, size + 1, (LPARAM)buffer); + buffer[size] = '\0'; + CString result(buffer); + delete[] buffer; + return result; +} + +HWND +getItem(HWND hwnd, int id) +{ + return GetDlgItem(hwnd, id); +} + +void +enableItem(HWND hwnd, int id, bool enabled) +{ + EnableWindow(GetDlgItem(hwnd, id), enabled); +} + +CString +getAppPath(const CString& appName) +{ + // prepare path to app + CPlatform platform; + char myPathname[MAX_PATH]; + GetModuleFileName(s_instance, myPathname, MAX_PATH); + const char* myBasename = platform.getBasename(myPathname); + CString appPath = CString(myPathname, myBasename - myPathname); + appPath += appName; + return appPath; +} + +static +bool +loadConfig(const CString& pathname, CConfig& config) +{ + try { + std::ifstream stream(pathname.c_str()); + if (stream) { + stream >> config; + return true; + } + } + catch (...) { + // ignore + } + return false; +} + +bool +loadConfig(CConfig& config) +{ + CPlatform platform; + + // load configuration + bool configLoaded = false; + CString path = platform.getUserDirectory(); + if (!path.empty()) { + CPlatform platform; + + // try loading the user's configuration + path = platform.addPathComponent(path, CONFIG_NAME); + if (loadConfig(path, config)) { + configLoaded = true; + } + else { + // try the system-wide config file + path = platform.getSystemDirectory(); + if (!path.empty()) { + path = platform.addPathComponent(path, CONFIG_NAME); + if (loadConfig(path, config)) { + configLoaded = true; + } + } + } + } + return configLoaded; +} + +static +bool +saveConfig(const CString& pathname, const CConfig& config) +{ + try { + std::ofstream stream(pathname.c_str()); + if (stream) { + stream << config; + return !!stream; + } + } + catch (...) { + // ignore + } + return false; +} + +bool +saveConfig(const CConfig& config, bool sysOnly) +{ + CPlatform platform; + + // try saving the user's configuration + if (!sysOnly) { + CString path = platform.getUserDirectory(); + if (!path.empty()) { + path = platform.addPathComponent(path, CONFIG_NAME); + if (saveConfig(path, config)) { + return true; + } + } + } + + // try the system-wide config file + else { + CString path = platform.getSystemDirectory(); + if (!path.empty()) { + path = platform.addPathComponent(path, CONFIG_NAME); + if (saveConfig(path, config)) { + return true; + } + } + } + + return false; +} diff --git a/cmd/launcher/LaunchUtil.h b/cmd/launcher/LaunchUtil.h new file mode 100755 index 00000000..414246e6 --- /dev/null +++ b/cmd/launcher/LaunchUtil.h @@ -0,0 +1,50 @@ +/* + * synergy -- mouse and keyboard sharing utility + * Copyright (C) 2002 Chris Schoeneman + * + * This package is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * found in the file COPYING that should have accompanied this file. + * + * This package is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef LAUNCHUTIL_H +#define LAUNCHUTIL_H + +#include "CString.h" + +#define WINDOWS_LEAN_AND_MEAN +#include + +#define CLIENT_APP "synergyc.exe" +#define SERVER_APP "synergys.exe" + +class CConfig; + +// client must define this and set it before calling any function here +extern HINSTANCE s_instance; + +CString getString(DWORD id); +CString getErrorString(DWORD error); + +void showError(HWND hwnd, const CString& msg); +void askOkay(HWND hwnd, const CString& title, + const CString& msg); +bool askVerify(HWND hwnd, const CString& msg); + +void setWindowText(HWND hwnd, const CString& msg); +CString getWindowText(HWND hwnd); + +HWND getItem(HWND hwnd, int id); +void enableItem(HWND hwnd, int id, bool enabled); + +CString getAppPath(const CString& appName); + +bool loadConfig(CConfig& config); +bool saveConfig(const CConfig& config, bool sysOnly); + +#endif diff --git a/cmd/launcher/launcher.cpp b/cmd/launcher/launcher.cpp index e18aa892..df1a9661 100644 --- a/cmd/launcher/launcher.cpp +++ b/cmd/launcher/launcher.cpp @@ -17,12 +17,12 @@ #include "CPlatform.h" #include "CNetwork.h" #include "Version.h" -#include "stdfstream.h" #include "stdvector.h" #include "resource.h" -#define WINDOWS_LEAN_AND_MEAN -#include +// these must come after the above because it includes windows.h +#include "LaunchUtil.h" +#include "CAutoStart.h" #define CONFIG_NAME "synergy.sgc" #define CLIENT_APP "synergyc.exe" @@ -45,9 +45,10 @@ public: HANDLE m_stop; }; +HINSTANCE s_instance = NULL; + static const TCHAR* s_mainClass = TEXT("GoSynergy"); static const TCHAR* s_layoutClass = TEXT("SynergyLayout"); -static HINSTANCE s_instance = NULL; static HWND s_mainWindow; static CConfig s_config; @@ -92,84 +93,6 @@ isNameInList(const CStringList& names, const CString& name) return false; } -static -CString -getString(DWORD id) -{ - char buffer[1024]; - buffer[0] = '\0'; - LoadString(s_instance, id, buffer, sizeof(buffer) / sizeof(buffer[0])); - return buffer; -} - -static -CString -getErrorString(DWORD error) -{ - char* buffer; - if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | - FORMAT_MESSAGE_IGNORE_INSERTS | - FORMAT_MESSAGE_FROM_SYSTEM, - 0, - error, - MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), - (LPTSTR)&buffer, - 0, - NULL) == 0) { - return getString(IDS_ERROR); - } - else { - CString result(buffer); - LocalFree(buffer); - return result; - } -} - -static -void -showError(HWND hwnd, const CString& msg) -{ - CString title = getString(IDS_ERROR); - MessageBox(hwnd, msg.c_str(), title.c_str(), MB_OK | MB_APPLMODAL); -} - -static -void -askOkay(HWND hwnd, const CString& title, const CString& msg) -{ - MessageBox(hwnd, msg.c_str(), title.c_str(), MB_OK | MB_APPLMODAL); -} - -static -bool -askVerify(HWND hwnd, const CString& msg) -{ - CString title = getString(IDS_VERIFY); - int result = MessageBox(hwnd, msg.c_str(), - title.c_str(), MB_OKCANCEL | MB_APPLMODAL); - return (result == IDOK); -} - -static -CString -getWindowText(HWND hwnd) -{ - LRESULT size = SendMessage(hwnd, WM_GETTEXTLENGTH, 0, 0); - char* buffer = new char[size + 1]; - SendMessage(hwnd, WM_GETTEXT, size + 1, (LPARAM)buffer); - buffer[size] = '\0'; - CString result(buffer); - delete[] buffer; - return result; -} - -static -void -enableItem(HWND hwnd, int id, bool enabled) -{ - EnableWindow(GetDlgItem(hwnd, id), enabled); -} - static bool isClientChecked(HWND hwnd) @@ -178,6 +101,13 @@ isClientChecked(HWND hwnd) return (SendMessage(child, BM_GETCHECK, 0, 0) == BST_CHECKED); } +static +void +enableSaveControls(HWND hwnd) +{ + enableItem(hwnd, IDC_MAIN_SAVE, s_config != s_oldConfig); +} + static void enableScreensControls(HWND hwnd) @@ -217,6 +147,7 @@ enableMainWindowControls(HWND hwnd) enableItem(hwnd, IDC_MAIN_CLIENT_SERVER_NAME_LABEL, client); enableItem(hwnd, IDC_MAIN_CLIENT_SERVER_NAME_EDIT, client); enableScreensControls(hwnd); + enableSaveControls(hwnd); } static @@ -310,6 +241,7 @@ addScreen(HWND hwnd) // update neighbors updateNeighbors(hwnd); enableScreensControls(hwnd); + enableSaveControls(hwnd); } } @@ -370,6 +302,7 @@ editScreen(HWND hwnd) // update neighbors updateNeighbors(hwnd); + enableSaveControls(hwnd); } } @@ -400,6 +333,7 @@ removeScreen(HWND hwnd) // update neighbors updateNeighbors(hwnd); enableScreensControls(hwnd); + enableSaveControls(hwnd); } static @@ -431,6 +365,8 @@ changeNeighbor(HWND hwnd, HWND combo, EDirection direction) s_config.connect(screen, direction, CString(neighbor)); delete[] neighbor; } + + enableSaveControls(hwnd); } static @@ -459,16 +395,16 @@ execApp(const char* app, const CString& cmdLine, PROCESS_INFORMATION* procInfo) startup.hStdError = NULL; // prepare path to app - CPlatform platform; - char myPathname[MAX_PATH]; - GetModuleFileName(s_instance, myPathname, MAX_PATH); - const char* myBasename = platform.getBasename(myPathname); - CString appPath = CString(myPathname, myBasename - myPathname); - appPath += app; + CString appPath = getAppPath(app); + + // put path to app in command line + CString commandLine = "\""; + commandLine += appPath; + commandLine += "\" "; + commandLine += cmdLine; // start child - if (CreateProcess(appPath.c_str(), - (char*)cmdLine.c_str(), + if (CreateProcess(NULL, (char*)commandLine.c_str(), NULL, NULL, FALSE, @@ -487,30 +423,11 @@ execApp(const char* app, const CString& cmdLine, PROCESS_INFORMATION* procInfo) } static -bool -uninstallApp(const char* app) -{ - PROCESS_INFORMATION procInfo; - - // uninstall - DWORD exitCode = kExitFailed; - if (execApp(app, "-z --uninstall", &procInfo)) { - WaitForSingleObject(procInfo.hProcess, INFINITE); - GetExitCodeProcess(procInfo.hProcess, &exitCode); - CloseHandle(procInfo.hProcess); - CloseHandle(procInfo.hThread); - } - - return (exitCode == kExitSuccess); -} - -static -HANDLE -launchApp(HWND hwnd, bool testing, DWORD* threadID) +CString +getCommandLine(HWND hwnd, bool testing) { // decide if client or server const bool isClient = isClientChecked(hwnd); - const char* app = isClient ? CLIENT_APP : SERVER_APP; // get and verify screen name HWND child = GetDlgItem(hwnd, IDC_MAIN_ADVANCED_NAME_EDIT); @@ -520,14 +437,14 @@ launchApp(HWND hwnd, bool testing, DWORD* threadID) getString(IDS_INVALID_SCREEN_NAME).c_str(), name.c_str())); SetFocus(child); - return NULL; + return CString(); } if (!isClient && !s_config.isScreen(name)) { showError(hwnd, CStringUtil::format( getString(IDS_UNKNOWN_SCREEN_NAME).c_str(), name.c_str())); SetFocus(child); - return NULL; + return CString(); } // get and verify port @@ -541,7 +458,7 @@ launchApp(HWND hwnd, bool testing, DWORD* threadID) portString.c_str(), defaultPortString.c_str())); SetFocus(child); - return NULL; + return CString(); } // prepare command line @@ -557,10 +474,10 @@ launchApp(HWND hwnd, bool testing, DWORD* threadID) CString server = getWindowText(child); if (!s_config.isValidScreenName(server)) { showError(hwnd, CStringUtil::format( - getString(IDS_INVALID_SCREEN_NAME).c_str(), + getString(IDS_INVALID_SERVER_NAME).c_str(), server.c_str())); SetFocus(child); - return NULL; + return CString(); } if (testing) { @@ -576,27 +493,21 @@ launchApp(HWND hwnd, bool testing, DWORD* threadID) cmdLine += portString; } - // uninstall client and server then reinstall one of them - if (!testing) { - // uninstall client and server - uninstallApp(CLIENT_APP); - uninstallApp(SERVER_APP); + return cmdLine; +} - // install client or server - PROCESS_INFORMATION procInfo; - DWORD exitCode = kExitFailed; - if (execApp(app, CString("-z --install") + cmdLine, &procInfo)) { - WaitForSingleObject(procInfo.hProcess, INFINITE); - GetExitCodeProcess(procInfo.hProcess, &exitCode); - CloseHandle(procInfo.hProcess); - CloseHandle(procInfo.hThread); - } +static +HANDLE +launchApp(HWND hwnd, bool testing, DWORD* threadID) +{ + // decide if client or server + const bool isClient = isClientChecked(hwnd); + const char* app = isClient ? CLIENT_APP : SERVER_APP; - // see if install succeeded - if (exitCode != kExitSuccess) { - showError(hwnd, getString(IDS_INSTALL_FAILED).c_str()); - return NULL; - } + // prepare command line + CString cmdLine = getCommandLine(hwnd, testing); + if (cmdLine.empty()) { + return NULL; } // start child @@ -716,67 +627,6 @@ waitForChild(HWND hwnd, HANDLE thread, DWORD threadID) CloseHandle(info.m_stop); } -static -bool -loadConfig(const CString& pathname, CConfig& config) -{ - try { - std::ifstream stream(pathname.c_str()); - if (stream) { - stream >> config; - return true; - } - } - catch (...) { - // ignore - } - return false; -} - -static -bool -saveConfig(const CString& pathname, const CConfig& config) -{ - try { - std::ofstream stream(pathname.c_str()); - if (stream) { - stream << config; - return !!stream; - } - } - catch (...) { - // ignore - } - return false; -} - -static -bool -saveConfig(const CConfig& config) -{ - CPlatform platform; - - CString path = platform.getUserDirectory(); - if (!path.empty()) { - // try loading the user's configuration - path = platform.addPathComponent(path, CONFIG_NAME); - if (saveConfig(path, config)) { - return true; - } - } - - // try the system-wide config file - path = platform.getSystemDirectory(); - if (!path.empty()) { - path = platform.addPathComponent(path, CONFIG_NAME); - if (saveConfig(path, config)) { - return true; - } - } - - return false; -} - static void initMainWindow(HWND hwnd) @@ -784,26 +634,9 @@ initMainWindow(HWND hwnd) CPlatform platform; // load configuration - bool configLoaded = false; - CString path = platform.getUserDirectory(); - if (!path.empty()) { - // try loading the user's configuration - path = platform.addPathComponent(path, CONFIG_NAME); - if (loadConfig(path, s_config)) { - configLoaded = true; - } - else { - // try the system-wide config file - path = platform.getSystemDirectory(); - if (!path.empty()) { - path = platform.addPathComponent(path, CONFIG_NAME); - if (loadConfig(path, s_config)) { - configLoaded = true; - } - } - } - } + bool configLoaded = loadConfig(s_config); s_oldConfig = s_config; + enableSaveControls(hwnd); // choose client/server radio buttons HWND child; @@ -978,82 +811,81 @@ mainWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) PostQuitMessage(0); return 0; - case IDOK: { - // save data - if (s_config != s_oldConfig) { - if (!saveConfig(s_config)) { - showError(hwnd, CStringUtil::format( - getString(IDS_SAVE_FAILED).c_str(), - getErrorString(GetLastError()).c_str())); - return 0; - } - s_oldConfig = s_config; - } - - // launch child app - HANDLE thread = launchApp(hwnd, false, NULL); - if (thread == NULL) { - return 0; - } - CloseHandle(thread); - - // notify of success - askOkay(hwnd, getString(IDS_STARTED_TITLE), - getString(IDS_STARTED)); - - // quit - PostQuitMessage(0); - return 0; - } - + case IDOK: case IDC_MAIN_TEST: { + // note if testing + const bool testing = (LOWORD(wParam) == IDC_MAIN_TEST); + // save data if (s_config != s_oldConfig) { - if (!saveConfig(s_config)) { + if (!saveConfig(s_config, false)) { showError(hwnd, CStringUtil::format( getString(IDS_SAVE_FAILED).c_str(), getErrorString(GetLastError()).c_str())); return 0; } s_oldConfig = s_config; + enableSaveControls(hwnd); } // launch child app DWORD threadID; - HANDLE thread = launchApp(hwnd, true, &threadID); + HANDLE thread = launchApp(hwnd, testing, &threadID); if (thread == NULL) { return 0; } - // wait for process to stop, allowing the user to kill it - waitForChild(hwnd, thread, threadID); + // handle child program + if (testing) { + // wait for process to stop, allowing the user to kill it + waitForChild(hwnd, thread, threadID); - // clean up - CloseHandle(thread); - return 0; - } - - case IDC_MAIN_UNINSTALL: { - // uninstall client and server - bool removedClient = uninstallApp(CLIENT_APP); - bool removedServer = uninstallApp(SERVER_APP); - if (!removedClient) { - showError(hwnd, CStringUtil::format( - getString(IDS_UNINSTALL_FAILED).c_str(), - getString(IDS_CLIENT).c_str())); - } - else if (!removedServer) { - showError(hwnd, CStringUtil::format( - getString(IDS_UNINSTALL_FAILED).c_str(), - getString(IDS_SERVER).c_str())); + // clean up + CloseHandle(thread); } else { - askOkay(hwnd, getString(IDS_UNINSTALL_TITLE), - getString(IDS_UNINSTALLED)); + // don't need thread handle + CloseHandle(thread); + + // notify of success + askOkay(hwnd, getString(IDS_STARTED_TITLE), + getString(IDS_STARTED)); + + // quit + PostQuitMessage(0); } return 0; } + case IDC_MAIN_AUTOSTART: { + // construct command line + CString cmdLine = getCommandLine(hwnd, false); + if (!cmdLine.empty()) { + // run dialog + CAutoStart autoStart(hwnd, + isClientChecked(hwnd) ? NULL : &s_config, + cmdLine); + autoStart.doModal(); + if (autoStart.wasUserConfigSaved()) { + s_oldConfig = s_config; + enableSaveControls(hwnd); + } + } + return 0; + } + + case IDC_MAIN_SAVE: + if (!saveConfig(s_config, false)) { + showError(hwnd, CStringUtil::format( + getString(IDS_SAVE_FAILED).c_str(), + getErrorString(GetLastError()).c_str())); + } + else { + s_oldConfig = s_config; + enableSaveControls(hwnd); + } + return 0; + case IDC_MAIN_CLIENT_RADIO: case IDC_MAIN_SERVER_RADIO: enableMainWindowControls(hwnd); diff --git a/cmd/launcher/launcher.dsp b/cmd/launcher/launcher.dsp index 79301495..f93739aa 100644 --- a/cmd/launcher/launcher.dsp +++ b/cmd/launcher/launcher.dsp @@ -95,18 +95,34 @@ LINK32=link.exe # PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" # Begin Source File +SOURCE=.\CAutoStart.cpp +# End Source File +# Begin Source File + SOURCE=.\launcher.cpp # End Source File # Begin Source File SOURCE=.\launcher.rc # End Source File +# Begin Source File + +SOURCE=.\LaunchUtil.cpp +# End Source File # End Group # Begin Group "Header Files" # PROP Default_Filter "h;hpp;hxx;hm;inl" # Begin Source File +SOURCE=.\CAutoStart.h +# End Source File +# Begin Source File + +SOURCE=.\LaunchUtil.h +# End Source File +# Begin Source File + SOURCE=.\resource.h # End Source File # End Group diff --git a/cmd/launcher/launcher.rc b/cmd/launcher/launcher.rc index f70cc55b..60ff371c 100644 --- a/cmd/launcher/launcher.rc +++ b/cmd/launcher/launcher.rc @@ -52,7 +52,7 @@ END // Dialog // -IDD_MAIN DIALOG DISCARDABLE 32768, 0, 300, 241 +IDD_MAIN DIALOG DISCARDABLE 32768, 0, 300, 262 STYLE DS_MODALFRAME | WS_MINIMIZEBOX | WS_CAPTION | WS_SYSMENU CAPTION "Synergy" CLASS "GoSynergy" @@ -62,22 +62,22 @@ BEGIN IDC_STATIC,7,7,286,19 GROUPBOX "",IDC_STATIC,7,29,286,31 GROUPBOX "",IDC_STATIC,7,67,286,103 - GROUPBOX "Advanced Options",IDC_STATIC,7,177,286,34 - CONTROL "Client",IDC_MAIN_CLIENT_RADIO,"Button", + GROUPBOX "Advanced Options",IDC_STATIC,7,177,286,56 + CONTROL "&Client",IDC_MAIN_CLIENT_RADIO,"Button", BS_AUTORADIOBUTTON | WS_GROUP | WS_TABSTOP,11,29,33,10 CONTROL "Server",IDC_MAIN_SERVER_RADIO,"Button", BS_AUTORADIOBUTTON,11,67,37,10 - LTEXT "Server Host Name:",IDC_MAIN_CLIENT_SERVER_NAME_LABEL,12, - 41,61,8 + LTEXT "Server &Host Name:",IDC_MAIN_CLIENT_SERVER_NAME_LABEL, + 12,41,61,8 EDITTEXT IDC_MAIN_CLIENT_SERVER_NAME_EDIT,79,39,106,12, ES_AUTOHSCROLL - LTEXT "Screens:",IDC_MAIN_SERVER_SCREENS_LABEL,12,79,29,8 + LTEXT "&Screens:",IDC_MAIN_SERVER_SCREENS_LABEL,12,79,29,8 LISTBOX IDC_MAIN_SERVER_SCREENS_LIST,12,91,106,36, LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP - PUSHBUTTON "Add",IDC_MAIN_SERVER_ADD_BUTTON,12,132,50,14 - PUSHBUTTON "Edit",IDC_MAIN_SERVER_EDIT_BUTTON,68,132,50,14 - PUSHBUTTON "Remove",IDC_MAIN_SERVER_REMOVE_BUTTON,12,150,50,14 - LTEXT "Layout:",IDC_MAIN_SERVER_LAYOUT_LABEL,138,79,24,8 + PUSHBUTTON "&Add",IDC_MAIN_SERVER_ADD_BUTTON,12,132,50,14 + PUSHBUTTON "&Edit",IDC_MAIN_SERVER_EDIT_BUTTON,68,132,50,14 + PUSHBUTTON "&Remove",IDC_MAIN_SERVER_REMOVE_BUTTON,12,150,50,14 + LTEXT "&Layout:",IDC_MAIN_SERVER_LAYOUT_LABEL,138,79,24,8 LTEXT "Left:",IDC_MAIN_SERVER_LEFT_LABEL,144,93,15,8 COMBOBOX IDC_MAIN_SERVER_LEFT_COMBO,175,91,118,46, CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL | WS_TABSTOP @@ -90,15 +90,17 @@ BEGIN LTEXT "Below:",IDC_MAIN_SERVER_BOTTOM_LABEL,144,141,22,8 COMBOBOX IDC_MAIN_SERVER_BOTTOM_COMBO,175,139,118,46, CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL | WS_TABSTOP - LTEXT "Screen Name:",IDC_STATIC,12,192,46,8 + LTEXT "Screen &Name:",IDC_STATIC,12,192,46,8 EDITTEXT IDC_MAIN_ADVANCED_NAME_EDIT,64,190,106,12,ES_AUTOHSCROLL - LTEXT "Port:",IDC_STATIC,194,192,16,8 + LTEXT "&Port:",IDC_STATIC,194,192,16,8 EDITTEXT IDC_MAIN_ADVANCED_PORT_EDIT,216,190,40,12,ES_AUTOHSCROLL | ES_NUMBER - DEFPUSHBUTTON "Test",IDC_MAIN_TEST,75,220,50,14 - PUSHBUTTON "Start",IDOK,131,220,50,14 - PUSHBUTTON "No Auto-Start",IDC_MAIN_UNINSTALL,187,220,50,14 - PUSHBUTTON "Quit",IDCANCEL,243,220,50,14 + LTEXT "Automatic Startup:",IDC_STATIC,12,212,59,8 + PUSHBUTTON "Con&figure...",IDC_MAIN_AUTOSTART,78,210,50,14 + PUSHBUTTON "Sa&ve",IDC_MAIN_SAVE,75,241,50,14 + DEFPUSHBUTTON "&Test",IDC_MAIN_TEST,131,241,50,14 + PUSHBUTTON "Start",IDOK,187,241,50,14 + PUSHBUTTON "Quit",IDCANCEL,243,241,50,14 END IDD_ADD DIALOG DISCARDABLE 0, 0, 172, 95 @@ -125,6 +127,26 @@ BEGIN IDC_STATIC,7,7,172,15 END +IDD_AUTOSTART DIALOG DISCARDABLE 0, 0, 195, 189 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Auto Start" +FONT 8, "MS Sans Serif" +BEGIN + DEFPUSHBUTTON "Close",IDCANCEL,138,168,50,14 + LTEXT "Synergy can be configured to start automatically when you log in. If you have sufficient access rights, you can instead configure synergy to start automatically when your computer starts.", + IDC_STATIC,7,7,181,33 + LTEXT "You have sufficient access rights to install and uninstall Auto Start for all users or for just yourself.", + IDC_AUTOSTART_PERMISSION_MSG,7,69,181,17 + LTEXT "Synergy is configured to start automatically when the system starts.", + IDC_AUTOSTART_INSTALLED_MSG,7,93,181,17 + GROUPBOX "When &You Log In",IDC_STATIC,7,119,84,40 + PUSHBUTTON "Install",IDC_AUTOSTART_INSTALL_USER,23,133,50,14 + GROUPBOX "When &Computer Starts",IDC_STATIC,104,119,84,40 + PUSHBUTTON "Install",IDC_AUTOSTART_INSTALL_SYSTEM,119,134,50,14 + LTEXT "Synergy can be configured to start automatically when the computer starts or when you log in but not both.", + IDC_STATIC,7,43,181,17 +END + ///////////////////////////////////////////////////////////////////////////// // @@ -139,7 +161,7 @@ BEGIN LEFTMARGIN, 7 RIGHTMARGIN, 293 TOPMARGIN, 7 - BOTTOMMARGIN, 234 + BOTTOMMARGIN, 255 END IDD_ADD, DIALOG @@ -157,6 +179,14 @@ BEGIN TOPMARGIN, 7 BOTTOMMARGIN, 47 END + + IDD_AUTOSTART, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 188 + TOPMARGIN, 7 + BOTTOMMARGIN, 182 + END END #endif // APSTUDIO_INVOKED @@ -189,16 +219,37 @@ BEGIN IDS_STARTUP_FAILED "Failed to start synergy: %{1}" IDS_STARTED_TITLE "Started" IDS_STARTED "Synergy was successfully started. Use the task manager to terminate it." - IDS_INSTALL_FAILED "Failed to install synergy auto-starter. Synergy will not be started now and it will not automatically start each time you start or reboot your computer." IDS_UNINSTALL_TITLE "Removed Auto-Start" - IDS_UNINSTALLED "Removed auto-start. Synergy will not automatically start each time you start or reboot your computer." END STRINGTABLE DISCARDABLE BEGIN - IDS_UNINSTALL_FAILED "Failed to remove auto-start of %{1}. You might not have permission to remove it or it might be in use.\n\nOn Windows NT, 2000, or XP you should open the Services control panel and stop the synergy %{1} service then try again." - IDS_CLIENT "client" - IDS_SERVER "server" + IDS_AUTOSTART_PERMISSION_SYSTEM + "You have sufficient access rights to install and uninstall Auto Start for all users or for just yourself." + IDS_AUTOSTART_PERMISSION_USER + "You have sufficient access rights to install and uninstall Auto Start for just yourself." + IDS_AUTOSTART_PERMISSION_NONE + "You do not have sufficient access rights to install or uninstall Auto Start." + IDS_AUTOSTART_INSTALLED_SYSTEM + "Synergy is configured to start automatically when the system starts." + IDS_AUTOSTART_INSTALLED_USER + "Synergy is configured to start automatically when you log in." + IDS_AUTOSTART_INSTALLED_NONE + "Synergy is not configured to start automatically." + IDS_INSTALL_LABEL "Install" + IDS_UNINSTALL_LABEL "Uninstall" + IDS_INSTALL_GENERIC_ERROR "Install failed for an unknown reason." + IDS_UNINSTALL_GENERIC_ERROR "Uninstall failed for an unknown reason." + IDS_INSTALL_TITLE "Installed Auto-Start" + IDS_INSTALLED_SYSTEM "Installed auto-start. Synergy will now automatically start each time you start your computer." + IDS_INSTALLED_USER "Installed auto-start. Synergy will now automatically start each time you log in." +END + +STRINGTABLE DISCARDABLE +BEGIN + IDS_UNINSTALLED_SYSTEM "Removed auto-start. Synergy will not automatically start each time you start or reboot your computer." + IDS_UNINSTALLED_USER "Removed auto-start. Synergy will not automatically start each time you log in." + IDS_INVALID_SERVER_NAME "Server name `%{1}' is invalid." END #endif // English (U.S.) resources diff --git a/cmd/launcher/resource.h b/cmd/launcher/resource.h index 679b3e97..93c263cf 100644 --- a/cmd/launcher/resource.h +++ b/cmd/launcher/resource.h @@ -1,62 +1,85 @@ -//{{NO_DEPENDENCIES}} -// Microsoft Developer Studio generated include file. -// Used by launcher.rc -// -#define IDS_ERROR 1 -#define IDS_INVALID_SCREEN_NAME 2 -#define IDS_DUPLICATE_SCREEN_NAME 3 -#define IDS_SCREEN_NAME_IS_ALIAS 4 -#define IDS_VERIFY 5 -#define IDS_UNSAVED_DATA_REALLY_QUIT 6 -#define IDS_UNKNOWN_SCREEN_NAME 7 -#define IDS_INVALID_PORT 8 -#define IDS_SAVE_FAILED 9 -#define IDS_STARTUP_FAILED 10 -#define IDS_STARTED_TITLE 11 -#define IDS_STARTED 12 -#define IDS_INSTALL_FAILED 13 -#define IDS_UNINSTALL_TITLE 14 -#define IDS_UNINSTALLED 15 -#define IDS_UNINSTALL_FAILED 16 -#define IDS_CLIENT 17 -#define IDS_SERVER 18 -#define IDD_MAIN 101 -#define IDD_ADD 102 -#define IDD_WAIT 103 -#define IDI_SYNERGY 104 -#define IDC_MAIN_CLIENT_RADIO 1000 -#define IDC_MAIN_SERVER_RADIO 1001 -#define IDC_MAIN_CLIENT_SERVER_NAME_EDIT 1002 -#define IDC_MAIN_ADVANCED_NAME_EDIT 1006 -#define IDC_MAIN_ADVANCED_PORT_EDIT 1008 -#define IDC_MAIN_TEST 1009 -#define IDC_MAIN_CLIENT_SERVER_NAME_LABEL 1011 -#define IDC_MAIN_SERVER_SCREENS_LIST 1012 -#define IDC_MAIN_SERVER_SCREENS_LABEL 1013 -#define IDC_MAIN_SERVER_LAYOUT_LABEL 1014 -#define IDC_MAIN_SERVER_ADD_BUTTON 1018 -#define IDC_MAIN_SERVER_EDIT_BUTTON 1019 -#define IDC_ADD_SCREEN_NAME_EDIT 1020 -#define IDC_MAIN_SERVER_REMOVE_BUTTON 1020 -#define IDC_ADD_ALIASES_EDIT 1021 -#define IDC_MAIN_SERVER_LEFT_COMBO 1022 -#define IDC_MAIN_SERVER_RIGHT_COMBO 1023 -#define IDC_MAIN_SERVER_TOP_COMBO 1024 -#define IDC_MAIN_SERVER_BOTTOM_COMBO 1025 -#define IDC_MAIN_SERVER_LEFT_LABEL 1026 -#define IDC_MAIN_SERVER_RIGHT_LABEL 1027 -#define IDC_MAIN_SERVER_TOP_LABEL 1028 -#define IDC_MAIN_SERVER_BOTTOM_LABEL 1029 -#define IDC_MAIN_UNINSTALL 1030 - -// Next default values for new objects -// -#ifdef APSTUDIO_INVOKED -#ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NO_MFC 1 -#define _APS_NEXT_RESOURCE_VALUE 105 -#define _APS_NEXT_COMMAND_VALUE 40001 -#define _APS_NEXT_CONTROL_VALUE 1031 -#define _APS_NEXT_SYMED_VALUE 101 -#endif -#endif +//{{NO_DEPENDENCIES}} +// Microsoft Developer Studio generated include file. +// Used by launcher.rc +// +#define IDS_ERROR 1 +#define IDS_INVALID_SCREEN_NAME 2 +#define IDS_DUPLICATE_SCREEN_NAME 3 +#define IDS_SCREEN_NAME_IS_ALIAS 4 +#define IDS_VERIFY 5 +#define IDS_UNSAVED_DATA_REALLY_QUIT 6 +#define IDS_UNKNOWN_SCREEN_NAME 7 +#define IDS_INVALID_PORT 8 +#define IDS_SAVE_FAILED 9 +#define IDS_STARTUP_FAILED 10 +#define IDS_STARTED_TITLE 11 +#define IDS_STARTED 12 +#define IDS_INSTALL_FAILED 13 +#define IDS_UNINSTALL_TITLE 14 +#define IDS_UNINSTALLED 15 +#define IDS_UNINSTALL_FAILED 16 +#define IDS_CLIENT 17 +#define IDS_SERVER 18 +#define IDS_AUTOSTART_PERMISSION_SYSTEM 19 +#define IDS_AUTOSTART_PERMISSION_USER 20 +#define IDS_AUTOSTART_PERMISSION_NONE 21 +#define IDS_AUTOSTART_INSTALLED_SYSTEM 22 +#define IDS_AUTOSTART_INSTALLED_USER 23 +#define IDS_AUTOSTART_INSTALLED_NONE 24 +#define IDS_INSTALL_LABEL 25 +#define IDS_UNINSTALL_LABEL 26 +#define IDS_INSTALL_GENERIC_ERROR 27 +#define IDS_UNINSTALL_GENERIC_ERROR 28 +#define IDS_INSTALL_TITLE 29 +#define IDS_INSTALLED_SYSTEM 30 +#define IDS_INSTALLED_USER 31 +#define IDS_UNINSTALLED_SYSTEM 32 +#define IDS_UNINSTALLED_USER 33 +#define IDS_INVALID_SERVER_NAME 34 +#define IDD_MAIN 101 +#define IDD_ADD 102 +#define IDD_WAIT 103 +#define IDI_SYNERGY 104 +#define IDD_AUTOSTART 105 +#define IDC_MAIN_CLIENT_RADIO 1000 +#define IDC_MAIN_SERVER_RADIO 1001 +#define IDC_MAIN_CLIENT_SERVER_NAME_EDIT 1002 +#define IDC_MAIN_ADVANCED_NAME_EDIT 1006 +#define IDC_MAIN_ADVANCED_PORT_EDIT 1008 +#define IDC_MAIN_TEST 1009 +#define IDC_MAIN_SAVE 1010 +#define IDC_MAIN_CLIENT_SERVER_NAME_LABEL 1011 +#define IDC_MAIN_SERVER_SCREENS_LIST 1012 +#define IDC_MAIN_SERVER_SCREENS_LABEL 1013 +#define IDC_MAIN_SERVER_LAYOUT_LABEL 1014 +#define IDC_MAIN_SERVER_ADD_BUTTON 1018 +#define IDC_MAIN_SERVER_EDIT_BUTTON 1019 +#define IDC_ADD_SCREEN_NAME_EDIT 1020 +#define IDC_MAIN_SERVER_REMOVE_BUTTON 1020 +#define IDC_ADD_ALIASES_EDIT 1021 +#define IDC_MAIN_SERVER_LEFT_COMBO 1022 +#define IDC_MAIN_SERVER_RIGHT_COMBO 1023 +#define IDC_MAIN_SERVER_TOP_COMBO 1024 +#define IDC_MAIN_SERVER_BOTTOM_COMBO 1025 +#define IDC_MAIN_SERVER_LEFT_LABEL 1026 +#define IDC_MAIN_SERVER_RIGHT_LABEL 1027 +#define IDC_MAIN_SERVER_TOP_LABEL 1028 +#define IDC_MAIN_SERVER_BOTTOM_LABEL 1029 +#define IDC_MAIN_UNINSTALL 1030 +#define IDC_AUTOSTART_INSTALLED_MSG 1031 +#define IDC_AUTOSTART_PERMISSION_MSG 1032 +#define IDC_AUTOSTART_INSTALL_USER 1033 +#define IDC_AUTOSTART_INSTALL_SYSTEM 1034 +#define IDC_MAIN_AUTOSTART 1035 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NO_MFC 1 +#define _APS_NEXT_RESOURCE_VALUE 106 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1036 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/cmd/synergyc/resource.h b/cmd/synergyc/resource.h index ec3e44aa..9c299850 100644 --- a/cmd/synergyc/resource.h +++ b/cmd/synergyc/resource.h @@ -1,19 +1,19 @@ -//{{NO_DEPENDENCIES}} -// Microsoft Developer Studio generated include file. -// Used by synergy.rc -// -#define IDS_FAILED 1 -#define IDD_SYNERGY 101 -#define IDI_SYNERGY 103 -#define IDC_LOG 1000 - -// Next default values for new objects -// -#ifdef APSTUDIO_INVOKED -#ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NEXT_RESOURCE_VALUE 104 -#define _APS_NEXT_COMMAND_VALUE 40001 -#define _APS_NEXT_CONTROL_VALUE 1000 -#define _APS_NEXT_SYMED_VALUE 101 -#endif -#endif +//{{NO_DEPENDENCIES}} +// Microsoft Developer Studio generated include file. +// Used by synergyc.rc +// +#define IDS_FAILED 1 +#define IDD_SYNERGY 101 +#define IDI_SYNERGY 103 +#define IDC_LOG 1000 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 104 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1000 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/cmd/synergyc/synergyc.cpp b/cmd/synergyc/synergyc.cpp index 94771f79..d2e45f31 100644 --- a/cmd/synergyc/synergyc.cpp +++ b/cmd/synergyc/synergyc.cpp @@ -54,8 +54,6 @@ static bool s_backend = false; static bool s_restartable = true; static bool s_daemon = true; static bool s_camp = true; -static bool s_install = false; -static bool s_uninstall = false; static const char* s_logFilter = NULL; static CString s_name; static CNetworkAddress s_serverAddress; @@ -246,25 +244,6 @@ static void help() { -#if WINDOWS_LIKE - -# define PLATFORM_ARGS \ -" [--install]" \ -" \n" \ -"or\n" \ -" --uninstall\n" -# define PLATFORM_DESC \ -" --install install server as a service.\n" \ -" --uninstall uninstall server service.\n" - -#else - -# define PLATFORM_ARGS \ -" \n" -# define PLATFORM_DESC - -#endif - log((CLOG_PRINT "Usage: %s" " [--camp|--no-camp]" @@ -272,7 +251,7 @@ help() " [--debug ]" " [--name ]" " [--restart|--no-restart]" -PLATFORM_ARGS +" \n" "\n" "Start the synergy mouse/keyboard sharing server.\n" "\n" @@ -289,7 +268,6 @@ PLATFORM_ARGS " -1, --no-restart do not try to restart the client if it fails for\n" " some reason.\n" "* --restart restart the client automatically if it fails.\n" -PLATFORM_DESC " -h, --help display this help and exit.\n" " --version display version information and exit.\n" "\n" @@ -397,30 +375,6 @@ parse(int argc, const char** argv) bye(kExitSuccess); } -#if WINDOWS_LIKE - else if (isArg(i, argc, argv, NULL, "--install")) { - s_install = true; - if (s_uninstall) { - log((CLOG_PRINT "%s: `--install' and `--uninstall'" - " are mutually exclusive" BYE, - pname, argv[i], pname)); - bye(kExitArgs); - } - } -#endif - -#if WINDOWS_LIKE - else if (isArg(i, argc, argv, NULL, "--uninstall")) { - s_uninstall = true; - if (s_install) { - log((CLOG_PRINT "%s: `--install' and `--uninstall'" - " are mutually exclusive" BYE, - pname, argv[i], pname)); - bye(kExitArgs); - } - } -#endif - else if (isArg(i, argc, argv, "--", NULL)) { // remaining arguments are not options ++i; @@ -439,37 +393,26 @@ parse(int argc, const char** argv) } } - // exactly one non-option argument (server-address) unless using - // --uninstall. - if (s_uninstall) { - if (i != argc) { - log((CLOG_PRINT "%s: unrecognized option `%s' to `%s'" BYE, - pname, argv[i], pname, - s_install ? "--install" : "--uninstall")); - bye(kExitArgs); - } - } - else { - if (i == argc) { - log((CLOG_PRINT "%s: a server address or name is required" BYE, + // exactly one non-option argument (server-address) + if (i == argc) { + log((CLOG_PRINT "%s: a server address or name is required" BYE, pname, pname)); - bye(kExitArgs); - } - if (i + 1 != argc) { - log((CLOG_PRINT "%s: unrecognized option `%s'" BYE, + bye(kExitArgs); + } + if (i + 1 != argc) { + log((CLOG_PRINT "%s: unrecognized option `%s'" BYE, pname, argv[i], pname)); - bye(kExitArgs); - } + bye(kExitArgs); + } - // save server address - try { - s_serverAddress = CNetworkAddress(argv[i], kDefaultPort); - } - catch (XSocketAddress& e) { - log((CLOG_PRINT "%s: %s" BYE, + // save server address + try { + s_serverAddress = CNetworkAddress(argv[i], kDefaultPort); + } + catch (XSocketAddress& e) { + log((CLOG_PRINT "%s: %s" BYE, pname, e.what(), pname)); - bye(kExitFailed); - } + bye(kExitFailed); } // increase default filter level for daemon. the user must @@ -496,7 +439,6 @@ parse(int argc, const char** argv) } } - // // platform dependent entry points // @@ -505,24 +447,16 @@ parse(int argc, const char** argv) #include "CMSWindowsScreen.h" -static bool s_errors = false; - static bool logMessageBox(int priority, const char* msg) { - if (priority <= CLog::kERROR) { - s_errors = true; - } - if (s_backend) { - return true; - } - if (priority <= CLog::kFATAL) { + if (priority <= (s_backend ? CLog::kERROR : CLog::kFATAL)) { MessageBox(NULL, msg, pname, MB_OK | MB_ICONWARNING); return true; } else { - return false; + return s_backend; } } @@ -551,13 +485,7 @@ daemonStartup(IPlatform* iplatform, int argc, const char** argv) bye = &byeThrow; // parse command line - s_install = false; - s_uninstall = false; parse(argc, argv); - if (s_install || s_uninstall) { - // not allowed to install/uninstall from service - throw CWin32Platform::CDaemonFailed(kExitArgs); - } // run as a service return platform->runDaemon(realMain, daemonStop); @@ -605,58 +533,6 @@ WinMain(HINSTANCE instance, HINSTANCE, LPSTR, int) // parse command line parse(__argc, const_cast(__argv)); - // install/uninstall - if (s_install) { - // get the full path to this program - TCHAR path[MAX_PATH]; - if (GetModuleFileName(NULL, path, - sizeof(path) / sizeof(path[0])) == 0) { - log((CLOG_CRIT "cannot determine absolute path to program")); - return kExitFailed; - } - - // construct the command line to start the service with - CString commandLine = "--daemon"; - if (s_restartable) { - commandLine += " --restart"; - } - else { - commandLine += " --no-restart"; - } - if (s_logFilter != NULL) { - commandLine += " --debug "; - commandLine += s_logFilter; - } - commandLine += " "; - commandLine += s_serverAddress.getHostname().c_str(); - - // install - if (!platform.installDaemon(DAEMON_NAME, - "Shares this system's mouse and keyboard with others.", - path, commandLine.c_str())) { - log((CLOG_CRIT "failed to install service")); - return kExitFailed; - } - log((CLOG_PRINT "installed successfully")); - return kExitSuccess; - } - else if (s_uninstall) { - switch (platform.uninstallDaemon(DAEMON_NAME)) { - case IPlatform::kSuccess: - log((CLOG_PRINT "uninstalled successfully")); - return kExitSuccess; - - case IPlatform::kFailed: - log((CLOG_CRIT "failed to uninstall service")); - return kExitFailed; - - case IPlatform::kAlready: - log((CLOG_CRIT "service isn't installed")); - // return success since service is uninstalled - return kExitSuccess; - } - } - // daemonize if requested int result; if (s_daemon) { @@ -684,15 +560,6 @@ WinMain(HINSTANCE instance, HINSTANCE, LPSTR, int) CNetwork::cleanup(); - // if running as a non-daemon backend and there was an error then - // wait for the user to click okay so he can see the error messages. - if (s_backend && !s_daemon && (result == kExitFailed || s_errors)) { - char msg[1024]; - msg[0] = '\0'; - LoadString(instance, IDS_FAILED, msg, sizeof(msg) / sizeof(msg[0])); - MessageBox(NULL, msg, pname, MB_OK | MB_ICONWARNING); - } - return result; } diff --git a/cmd/synergyc/synergyc.rc b/cmd/synergyc/synergyc.rc index 097279bb..f1523300 100644 --- a/cmd/synergyc/synergyc.rc +++ b/cmd/synergyc/synergyc.rc @@ -89,17 +89,6 @@ END // Icon with lowest ID value placed first to ensure application icon // remains consistent on all systems. IDI_SYNERGY ICON DISCARDABLE "synergyc.ico" - -///////////////////////////////////////////////////////////////////////////// -// -// String Table -// - -STRINGTABLE DISCARDABLE -BEGIN - IDS_FAILED "Synergy is about to quit with an error. Please check the log for error messages then click OK." -END - #endif // English (U.S.) resources ///////////////////////////////////////////////////////////////////////////// diff --git a/cmd/synergys/resource.h b/cmd/synergys/resource.h index 5b67a903..6142fc38 100644 --- a/cmd/synergys/resource.h +++ b/cmd/synergys/resource.h @@ -1,19 +1,19 @@ -//{{NO_DEPENDENCIES}} -// Microsoft Developer Studio generated include file. -// Used by synergyd.rc -// -#define IDS_FAILED 1 -#define IDD_SYNERGY 101 -#define IDI_SYNERGY 102 -#define IDC_LOG 1000 - -// Next default values for new objects -// -#ifdef APSTUDIO_INVOKED -#ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NEXT_RESOURCE_VALUE 103 -#define _APS_NEXT_COMMAND_VALUE 40001 -#define _APS_NEXT_CONTROL_VALUE 1002 -#define _APS_NEXT_SYMED_VALUE 101 -#endif -#endif +//{{NO_DEPENDENCIES}} +// Microsoft Developer Studio generated include file. +// Used by synergyd.rc +// +#define IDS_FAILED 1 +#define IDD_SYNERGY 101 +#define IDI_SYNERGY 102 +#define IDC_LOG 1000 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 103 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1002 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/cmd/synergys/synergys.cpp b/cmd/synergys/synergys.cpp index 0d0a479f..496cf5a7 100644 --- a/cmd/synergys/synergys.cpp +++ b/cmd/synergys/synergys.cpp @@ -61,10 +61,6 @@ static const char* pname = NULL; static bool s_backend = false; static bool s_restartable = true; static bool s_daemon = true; -#if WINDOWS_LIKE -static bool s_install = false; -static bool s_uninstall = false; -#endif static const char* s_configFile = NULL; static const char* s_logFilter = NULL; static CString s_name; @@ -275,13 +271,8 @@ help() #if WINDOWS_LIKE # define PLATFORM_ARGS \ -" {--daemon|--no-daemon}" \ -" [--install]\n" \ -"or\n" \ -" --uninstall\n" -# define PLATFORM_DESC \ -" --install install server as a daemon.\n" \ -" --uninstall uninstall server daemon.\n" +" {--daemon|--no-daemon}" +# define PLATFORM_DESC # define PLATFORM_EXTRA \ "At least one command line argument is required. If you don't otherwise\n" \ "need an argument use `--daemon'.\n" \ @@ -334,7 +325,7 @@ PLATFORM_EXTRA "default port, %d.\n" "\n" "If no configuration file pathname is provided then the first of the\n" -"following to load sets the configuration:\n" +"following to load successfully sets the configuration:\n" " %s\n" " %s\n" "If no configuration file can be loaded then the configuration uses its\n" @@ -465,30 +456,6 @@ parse(int argc, const char** argv) bye(kExitSuccess); } -#if WINDOWS_LIKE - else if (isArg(i, argc, argv, NULL, "--install")) { - s_install = true; - if (s_uninstall) { - log((CLOG_PRINT "%s: `--install' and `--uninstall'" - " are mutually exclusive" BYE, - pname, argv[i], pname)); - bye(kExitArgs); - } - } -#endif - -#if WINDOWS_LIKE - else if (isArg(i, argc, argv, NULL, "--uninstall")) { - s_uninstall = true; - if (s_install) { - log((CLOG_PRINT "%s: `--install' and `--uninstall'" - " are mutually exclusive" BYE, - pname, argv[i], pname)); - bye(kExitArgs); - } - } -#endif - else if (isArg(i, argc, argv, "--", NULL)) { // remaining arguments are not options ++i; @@ -612,24 +579,16 @@ loadConfig() #include "CMSWindowsScreen.h" -static bool s_errors = false; - static bool logMessageBox(int priority, const char* msg) { - if (priority <= CLog::kERROR) { - s_errors = true; - } - if (s_backend) { - return true; - } - if (priority <= CLog::kFATAL) { + if (priority <= (s_backend ? CLog::kERROR : CLog::kFATAL)) { MessageBox(NULL, msg, pname, MB_OK | MB_ICONWARNING); return true; } else { - return false; + return s_backend; } } @@ -658,13 +617,7 @@ daemonStartup(IPlatform* iplatform, int argc, const char** argv) bye = &byeThrow; // parse command line - s_install = false; - s_uninstall = false; parse(argc, argv); - if (s_install || s_uninstall) { - // not allowed to install/uninstall from service - throw CWin32Platform::CDaemonFailed(kExitArgs); - } // load configuration loadConfig(); @@ -715,62 +668,6 @@ WinMain(HINSTANCE instance, HINSTANCE, LPSTR, int) // parse command line parse(__argc, const_cast(__argv)); - // install/uninstall - if (s_install) { - // get the full path to this program - TCHAR path[MAX_PATH]; - if (GetModuleFileName(NULL, path, - sizeof(path) / sizeof(path[0])) == 0) { - log((CLOG_CRIT "cannot determine absolute path to program")); - return kExitFailed; - } - - // construct the command line to start the service with - CString commandLine; - commandLine += "--daemon"; - if (s_restartable) { - commandLine += " --restart"; - } - else { - commandLine += " --no-restart"; - } - if (s_logFilter != NULL) { - commandLine += " --debug "; - commandLine += s_logFilter; - } - if (s_configFile != NULL) { - commandLine += " --config \""; - commandLine += s_configFile; - commandLine += "\""; - } - - // install - if (!platform.installDaemon(DAEMON_NAME, - "Shares this system's mouse and keyboard with others.", - path, commandLine.c_str())) { - log((CLOG_CRIT "failed to install service")); - return kExitFailed; - } - log((CLOG_PRINT "installed successfully")); - return kExitSuccess; - } - else if (s_uninstall) { - switch (platform.uninstallDaemon(DAEMON_NAME)) { - case IPlatform::kSuccess: - log((CLOG_PRINT "uninstalled successfully")); - return kExitSuccess; - - case IPlatform::kFailed: - log((CLOG_CRIT "failed to uninstall service")); - return kExitFailed; - - case IPlatform::kAlready: - log((CLOG_CRIT "service isn't installed")); - // return success since service is uninstalled - return kExitSuccess; - } - } - // load configuration loadConfig(); @@ -801,15 +698,6 @@ WinMain(HINSTANCE instance, HINSTANCE, LPSTR, int) CNetwork::cleanup(); - // if running as a non-daemon backend and there was an error then - // wait for the user to click okay so he can see the error messages. - if (s_backend && !s_daemon && (result == kExitFailed || s_errors)) { - char msg[1024]; - msg[0] = '\0'; - LoadString(instance, IDS_FAILED, msg, sizeof(msg) / sizeof(msg[0])); - MessageBox(NULL, msg, pname, MB_OK | MB_ICONWARNING); - } - return result; } diff --git a/lib/client/CClient.cpp b/lib/client/CClient.cpp index b4c5cbda..de6b086d 100644 --- a/lib/client/CClient.cpp +++ b/lib/client/CClient.cpp @@ -511,7 +511,7 @@ CClient::runServer() for (;;) { try { // allow connect this much time to succeed - CTimerThread timer(m_camp ? -1.0 : 30.0); + CTimerThread timer(15.0); // create socket and attempt to connect to server log((CLOG_DEBUG1 "connecting to server")); @@ -532,7 +532,7 @@ CClient::runServer() } // we're camping. wait a bit before retrying - CThread::sleep(5.0); + CThread::sleep(15.0); } } diff --git a/lib/client/CMSWindowsSecondaryScreen.cpp b/lib/client/CMSWindowsSecondaryScreen.cpp index a7301199..5a96156e 100644 --- a/lib/client/CMSWindowsSecondaryScreen.cpp +++ b/lib/client/CMSWindowsSecondaryScreen.cpp @@ -459,6 +459,7 @@ CMSWindowsSecondaryScreen::updateKeys() if ((m_keys[VK_SCROLL] & 0x01) != 0) { m_mask |= KeyModifierScrollLock; } + // note -- do not save KeyModifierModeSwitch in m_mask log((CLOG_DEBUG2 "modifiers on update: 0x%04x", m_mask)); } @@ -634,6 +635,11 @@ CMSWindowsSecondaryScreen::mapKey(Keystrokes& keys, UINT& virtualKey, KeyModifierAlt | KeyModifierMeta)); + // set control and alt if mode shift (AltGr) is requested + if ((mask & KeyModifierModeSwitch) != 0) { + outMask |= KeyModifierControl | KeyModifierAlt; + } + // extract extended key flag const bool isExtended = ((virtualKey & 0x100) != 0); virtualKey &= ~0x100; diff --git a/lib/platform/CUnixPlatform.cpp b/lib/platform/CUnixPlatform.cpp index 0a6518c2..f0e447eb 100644 --- a/lib/platform/CUnixPlatform.cpp +++ b/lib/platform/CUnixPlatform.cpp @@ -38,14 +38,15 @@ CUnixPlatform::~CUnixPlatform() } bool -CUnixPlatform::installDaemon(const char*, const char*, const char*, const char*) +CUnixPlatform::installDaemon(const char*, const char*, + const char*, const char*, bool) { // daemons don't require special installation return true; } CUnixPlatform::EResult -CUnixPlatform::uninstallDaemon(const char*) +CUnixPlatform::uninstallDaemon(const char*, bool) { // daemons don't require special installation return kSuccess; @@ -106,6 +107,18 @@ CUnixPlatform::installDaemonLogger(const char* name) CLog::setOutputter(&CUnixPlatform::deamonLogger); } +bool +CUnixPlatform::canInstallDaemon(const char*, bool) const +{ + return false; +} + +bool +CUnixPlatform::isDaemonInstalled(const char*, bool) const +{ + return false; +} + const char* CUnixPlatform::getBasename(const char* pathname) const { diff --git a/lib/platform/CUnixPlatform.h b/lib/platform/CUnixPlatform.h index 91f73565..00e5ea23 100644 --- a/lib/platform/CUnixPlatform.h +++ b/lib/platform/CUnixPlatform.h @@ -27,10 +27,15 @@ public: virtual bool installDaemon(const char* name, const char* description, const char* pathname, - const char* commandLine); - virtual EResult uninstallDaemon(const char* name); + const char* commandLine, + bool allUsers); + virtual EResult uninstallDaemon(const char* name, bool allUsers); virtual int daemonize(const char* name, DaemonFunc); virtual void installDaemonLogger(const char* name); + virtual bool canInstallDaemon(const char* name, + bool allUsers) const; + virtual bool isDaemonInstalled(const char* name, + bool allUsers) const; virtual const char* getBasename(const char* pathname) const; virtual CString getUserDirectory() const; virtual CString getSystemDirectory() const; diff --git a/lib/platform/CWin32Platform.cpp b/lib/platform/CWin32Platform.cpp index f2d5c1ba..29dece5b 100644 --- a/lib/platform/CWin32Platform.cpp +++ b/lib/platform/CWin32Platform.cpp @@ -94,14 +94,16 @@ CWin32Platform::setStatusError(SERVICE_STATUS_HANDLE handle, DWORD error) bool CWin32Platform::installDaemon(const char* name, const char* description, - const char* pathname, const char* commandLine) + const char* pathname, const char* commandLine, bool allUsers) { - // windows 95 family services - if (isWindows95Family()) { + // if not for all users then use the user's autostart registry. + // key. if windows 95 family then use windows 95 services key. + if (!allUsers || isWindows95Family()) { // open registry - HKEY key = open95ServicesKey(); + HKEY key = isWindows95Family() ? open95ServicesKey() : + openUserStartupKey(); if (key == NULL) { - log((CLOG_ERR "cannot open RunServices registry key", GetLastError())); + log((CLOG_ERR "cannot open registry key", GetLastError())); return false; } @@ -152,6 +154,8 @@ CWin32Platform::installDaemon(const char* name, const char* description, CloseServiceHandle(mgr); } else { +// FIXME -- handle ERROR_SERVICE_EXISTS + log((CLOG_ERR "CreateService failed with %d", GetLastError())); CloseServiceHandle(mgr); return false; @@ -162,7 +166,7 @@ CWin32Platform::installDaemon(const char* name, const char* description, key = openKey(key, name); if (key == NULL) { // can't open key - uninstallDaemon(name); + uninstallDaemon(name, allUsers); return false; } @@ -173,7 +177,7 @@ CWin32Platform::installDaemon(const char* name, const char* description, key = openKey(key, "Parameters"); if (key == NULL) { // can't open key - uninstallDaemon(name); + uninstallDaemon(name, allUsers); return false; } setValue(key, "CommandLine", commandLine); @@ -186,14 +190,16 @@ CWin32Platform::installDaemon(const char* name, const char* description, } IPlatform::EResult -CWin32Platform::uninstallDaemon(const char* name) +CWin32Platform::uninstallDaemon(const char* name, bool allUsers) { - // windows 95 family services - if (isWindows95Family()) { + // if not for all users then use the user's autostart registry. + // key. if windows 95 family then use windows 95 services key. + if (!allUsers || isWindows95Family()) { // open registry - HKEY key = open95ServicesKey(); + HKEY key = isWindows95Family() ? open95ServicesKey() : + openUserStartupKey(); if (key == NULL) { - log((CLOG_ERR "cannot open RunServices registry key", GetLastError())); + log((CLOG_ERR "cannot open registry key", GetLastError())); return kAlready; } @@ -334,6 +340,91 @@ CWin32Platform::installDaemonLogger(const char* name) } } +bool +CWin32Platform::canInstallDaemon(const char* name, bool allUsers) const +{ + // if not for all users then use the user's autostart registry. + // key. if windows 95 family then use windows 95 services key. + if (!allUsers || isWindows95Family()) { + // check if we can open the registry key + HKEY key = isWindows95Family() ? open95ServicesKey() : + openUserStartupKey(); + closeKey(key); + return (key != NULL); + } + + // windows NT family services + else { + // check if we can open service manager for write + SC_HANDLE mgr = OpenSCManager(NULL, NULL, GENERIC_WRITE); + if (mgr == NULL) { + return false; + } + CloseServiceHandle(mgr); + + // check if we can open the registry key for this service + HKEY key = openNTServicesKey(); + key = openKey(key, name); + key = openKey(key, "Parameters"); + closeKey(key); + + return (key != NULL); + } +} + +bool +CWin32Platform::isDaemonInstalled(const char* name, bool allUsers) const +{ + // if not for all users then use the user's autostart registry. + // key. if windows 95 family then use windows 95 services key. + if (!allUsers || isWindows95Family()) { + // check if we can open the registry key + HKEY key = isWindows95Family() ? open95ServicesKey() : + openUserStartupKey(); + if (key == NULL) { + return false; + } + + // check for entry + const bool installed = !readValueString(key, name).empty(); + + // clean up + closeKey(key); + + return installed; + } + + // windows NT family services + else { + // check parameters for this service + HKEY key = openNTServicesKey(); + key = openKey(key, name); + key = openKey(key, "Parameters"); + if (key != NULL) { + const bool installed = !readValueString(key, "CommandLine").empty(); + closeKey(key); + if (!installed) { + return false; + } + } + + // open service manager + SC_HANDLE mgr = OpenSCManager(NULL, NULL, GENERIC_READ); + if (mgr == NULL) { + return false; + } + + // open the service + SC_HANDLE service = OpenService(mgr, name, GENERIC_READ); + + // clean up + CloseServiceHandle(service); + CloseServiceHandle(mgr); + + return (service != NULL); + } +} + const char* CWin32Platform::getBasename(const char* pathname) const { @@ -436,6 +527,11 @@ CWin32Platform::addPathComponent(const CString& prefix, HKEY CWin32Platform::openKey(HKEY key, const char* keyName) { + // ignore if parent is NULL + if (key == NULL) { + return NULL; + } + // open next key HKEY newKey; LONG result = RegOpenKeyEx(key, keyName, 0, @@ -555,6 +651,21 @@ CWin32Platform::open95ServicesKey() return openKey(HKEY_LOCAL_MACHINE, s_keyNames); } +HKEY +CWin32Platform::openUserStartupKey() +{ + static const char* s_keyNames[] = { + _T("Software"), + _T("Microsoft"), + _T("Windows"), + _T("CurrentVersion"), + _T("Run"), + NULL + }; + + return openKey(HKEY_CURRENT_USER, s_keyNames); +} + int CWin32Platform::runDaemon(RunFunc run, StopFunc stop) { diff --git a/lib/platform/CWin32Platform.h b/lib/platform/CWin32Platform.h index 644d4408..dadcb4f2 100644 --- a/lib/platform/CWin32Platform.h +++ b/lib/platform/CWin32Platform.h @@ -71,10 +71,15 @@ public: virtual bool installDaemon(const char* name, const char* description, const char* pathname, - const char* commandLine); - virtual EResult uninstallDaemon(const char* name); + const char* commandLine, + bool allUsers); + virtual EResult uninstallDaemon(const char* name, bool allUsers); virtual int daemonize(const char* name, DaemonFunc); virtual void installDaemonLogger(const char* name); + virtual bool canInstallDaemon(const char* name, + bool allUsers) const; + virtual bool isDaemonInstalled(const char* name, + bool allUsers) const; virtual const char* getBasename(const char* pathname) const; virtual CString getUserDirectory() const; virtual CString getSystemDirectory() const; @@ -93,6 +98,7 @@ private: static CString readValueString(HKEY, const char* name); static HKEY openNTServicesKey(); static HKEY open95ServicesKey(); + static HKEY openUserStartupKey(); void serviceMain(DWORD, LPTSTR*); static void WINAPI serviceMainEntry(DWORD, LPTSTR*); diff --git a/lib/platform/IPlatform.h b/lib/platform/IPlatform.h index 95d10cdb..2962f4f2 100644 --- a/lib/platform/IPlatform.h +++ b/lib/platform/IPlatform.h @@ -43,18 +43,22 @@ public: system and \c description is a short human readable description of the daemon. \c pathname is the path to the daemon executable. \c commandLine should \b not include the name of program as the - first argument. + first argument. If \c allUsers is true then the daemon will be + installed to start at boot time, otherwise it will be installed to + start when the current user logs in. */ // FIXME -- throw on error? will get better error messages that way. virtual bool installDaemon(const char* name, const char* description, const char* pathname, - const char* commandLine) = 0; + const char* commandLine, + bool allUsers) = 0; + //! Uninstall daemon /*! Uninstall a daemon. */ - virtual EResult uninstallDaemon(const char* name) = 0; + virtual EResult uninstallDaemon(const char* name, bool allUsers) = 0; //! Daemonize the process /*! @@ -91,6 +95,24 @@ public: //! @name accessors //@{ + //! Check if user has permission to install the daemon + /*! + Returns true iff the caller has permission to install or + uninstall the daemon. Note that even if this method returns + true it's possible that installing/uninstalling the service + may still fail. This method ignores whether or not the + service is already installed. + */ + virtual bool canInstallDaemon(const char* name, + bool allUsers) const = 0; + + //! Check if the daemon is installed + /*! + Returns true iff the daemon is installed. + */ + virtual bool isDaemonInstalled(const char* name, + bool allUsers) const = 0; + //! Extract base name /*! Find the base name in the given \c pathname. diff --git a/lib/server/CMSWindowsPrimaryScreen.cpp b/lib/server/CMSWindowsPrimaryScreen.cpp index b9622694..0bd15164 100644 --- a/lib/server/CMSWindowsPrimaryScreen.cpp +++ b/lib/server/CMSWindowsPrimaryScreen.cpp @@ -614,264 +614,266 @@ CMSWindowsPrimaryScreen::ignore() const return (m_mark != m_markReceived); } -static const KeyID g_virtualKey[] = +// map virtual keys to synergy key enumeration. use extended keyboard +// bit to distinguish some keys. +static const KeyID g_virtualKey[][2] = { - /* 0x00 */ kKeyNone, // reserved - /* 0x01 */ kKeyNone, // VK_LBUTTON - /* 0x02 */ kKeyNone, // VK_RBUTTON - /* 0x03 */ kKeyBreak, // VK_CANCEL - /* 0x04 */ kKeyNone, // VK_MBUTTON - /* 0x05 */ kKeyNone, // undefined - /* 0x06 */ kKeyNone, // undefined - /* 0x07 */ kKeyNone, // undefined - /* 0x08 */ kKeyBackSpace, // VK_BACK - /* 0x09 */ kKeyTab, // VK_TAB - /* 0x0a */ kKeyNone, // undefined - /* 0x0b */ kKeyNone, // undefined - /* 0x0c */ kKeyClear, // VK_CLEAR - /* 0x0d */ kKeyReturn, // VK_RETURN - /* 0x0e */ kKeyNone, // undefined - /* 0x0f */ kKeyNone, // undefined - /* 0x10 */ kKeyShift_L, // VK_SHIFT - /* 0x11 */ kKeyControl_L, // VK_CONTROL - /* 0x12 */ kKeyAlt_L, // VK_MENU - /* 0x13 */ kKeyPause, // VK_PAUSE - /* 0x14 */ kKeyCapsLock, // VK_CAPITAL - /* 0x15 */ kKeyNone, // VK_KANA - /* 0x16 */ kKeyNone, // VK_HANGUL - /* 0x17 */ kKeyNone, // VK_JUNJA - /* 0x18 */ kKeyNone, // VK_FINAL - /* 0x19 */ kKeyNone, // VK_KANJI - /* 0x1a */ kKeyNone, // undefined - /* 0x1b */ kKeyEscape, // VK_ESCAPE - /* 0x1c */ kKeyNone, // VK_CONVERT - /* 0x1d */ kKeyNone, // VK_NONCONVERT - /* 0x1e */ kKeyNone, // VK_ACCEPT - /* 0x1f */ kKeyNone, // VK_MODECHANGE - /* 0x20 */ 0x0020, // VK_SPACE - /* 0x21 */ kKeyPageUp, // VK_PRIOR - /* 0x22 */ kKeyPageDown, // VK_NEXT - /* 0x23 */ kKeyEnd, // VK_END - /* 0x24 */ kKeyHome, // VK_HOME - /* 0x25 */ kKeyLeft, // VK_LEFT - /* 0x26 */ kKeyUp, // VK_UP - /* 0x27 */ kKeyRight, // VK_RIGHT - /* 0x28 */ kKeyDown, // VK_DOWN - /* 0x29 */ kKeySelect, // VK_SELECT - /* 0x2a */ kKeyNone, // VK_PRINT - /* 0x2b */ kKeyExecute, // VK_EXECUTE - /* 0x2c */ kKeyPrint, // VK_SNAPSHOT - /* 0x2d */ kKeyInsert, // VK_INSERT - /* 0x2e */ kKeyDelete, // VK_DELETE - /* 0x2f */ kKeyHelp, // VK_HELP - /* 0x30 */ kKeyNone, // VK_0 - /* 0x31 */ kKeyNone, // VK_1 - /* 0x32 */ kKeyNone, // VK_2 - /* 0x33 */ kKeyNone, // VK_3 - /* 0x34 */ kKeyNone, // VK_4 - /* 0x35 */ kKeyNone, // VK_5 - /* 0x36 */ kKeyNone, // VK_6 - /* 0x37 */ kKeyNone, // VK_7 - /* 0x38 */ kKeyNone, // VK_8 - /* 0x39 */ kKeyNone, // VK_9 - /* 0x3a */ kKeyNone, // undefined - /* 0x3b */ kKeyNone, // undefined - /* 0x3c */ kKeyNone, // undefined - /* 0x3d */ kKeyNone, // undefined - /* 0x3e */ kKeyNone, // undefined - /* 0x3f */ kKeyNone, // undefined - /* 0x40 */ kKeyNone, // undefined - /* 0x41 */ kKeyNone, // VK_A - /* 0x42 */ kKeyNone, // VK_B - /* 0x43 */ kKeyNone, // VK_C - /* 0x44 */ kKeyNone, // VK_D - /* 0x45 */ kKeyNone, // VK_E - /* 0x46 */ kKeyNone, // VK_F - /* 0x47 */ kKeyNone, // VK_G - /* 0x48 */ kKeyNone, // VK_H - /* 0x49 */ kKeyNone, // VK_I - /* 0x4a */ kKeyNone, // VK_J - /* 0x4b */ kKeyNone, // VK_K - /* 0x4c */ kKeyNone, // VK_L - /* 0x4d */ kKeyNone, // VK_M - /* 0x4e */ kKeyNone, // VK_N - /* 0x4f */ kKeyNone, // VK_O - /* 0x50 */ kKeyNone, // VK_P - /* 0x51 */ kKeyNone, // VK_Q - /* 0x52 */ kKeyNone, // VK_R - /* 0x53 */ kKeyNone, // VK_S - /* 0x54 */ kKeyNone, // VK_T - /* 0x55 */ kKeyNone, // VK_U - /* 0x56 */ kKeyNone, // VK_V - /* 0x57 */ kKeyNone, // VK_W - /* 0x58 */ kKeyNone, // VK_X - /* 0x59 */ kKeyNone, // VK_Y - /* 0x5a */ kKeyNone, // VK_Z - /* 0x5b */ kKeyMeta_L, // VK_LWIN - /* 0x5c */ kKeyMeta_R, // VK_RWIN - /* 0x5d */ kKeyMenu, // VK_APPS - /* 0x5e */ kKeyNone, // undefined - /* 0x5f */ kKeyNone, // undefined - /* 0x60 */ kKeyKP_0, // VK_NUMPAD0 - /* 0x61 */ kKeyKP_1, // VK_NUMPAD1 - /* 0x62 */ kKeyKP_2, // VK_NUMPAD2 - /* 0x63 */ kKeyKP_3, // VK_NUMPAD3 - /* 0x64 */ kKeyKP_4, // VK_NUMPAD4 - /* 0x65 */ kKeyKP_5, // VK_NUMPAD5 - /* 0x66 */ kKeyKP_6, // VK_NUMPAD6 - /* 0x67 */ kKeyKP_7, // VK_NUMPAD7 - /* 0x68 */ kKeyKP_8, // VK_NUMPAD8 - /* 0x69 */ kKeyKP_9, // VK_NUMPAD9 - /* 0x6a */ kKeyKP_Multiply, // VK_MULTIPLY - /* 0x6b */ kKeyKP_Add, // VK_ADD - /* 0x6c */ kKeyKP_Separator,// VK_SEPARATOR - /* 0x6d */ kKeyKP_Subtract, // VK_SUBTRACT - /* 0x6e */ kKeyKP_Decimal, // VK_DECIMAL - /* 0x6f */ kKeyKP_Divide, // VK_DIVIDE - /* 0x70 */ kKeyF1, // VK_F1 - /* 0x71 */ kKeyF2, // VK_F2 - /* 0x72 */ kKeyF3, // VK_F3 - /* 0x73 */ kKeyF4, // VK_F4 - /* 0x74 */ kKeyF5, // VK_F5 - /* 0x75 */ kKeyF6, // VK_F6 - /* 0x76 */ kKeyF7, // VK_F7 - /* 0x77 */ kKeyF8, // VK_F8 - /* 0x78 */ kKeyF9, // VK_F9 - /* 0x79 */ kKeyF10, // VK_F10 - /* 0x7a */ kKeyF11, // VK_F11 - /* 0x7b */ kKeyF12, // VK_F12 - /* 0x7c */ kKeyF13, // VK_F13 - /* 0x7d */ kKeyF14, // VK_F14 - /* 0x7e */ kKeyF15, // VK_F15 - /* 0x7f */ kKeyF16, // VK_F16 - /* 0x80 */ kKeyF17, // VK_F17 - /* 0x81 */ kKeyF18, // VK_F18 - /* 0x82 */ kKeyF19, // VK_F19 - /* 0x83 */ kKeyF20, // VK_F20 - /* 0x84 */ kKeyF21, // VK_F21 - /* 0x85 */ kKeyF22, // VK_F22 - /* 0x86 */ kKeyF23, // VK_F23 - /* 0x87 */ kKeyF24, // VK_F24 - /* 0x88 */ kKeyNone, // unassigned - /* 0x89 */ kKeyNone, // unassigned - /* 0x8a */ kKeyNone, // unassigned - /* 0x8b */ kKeyNone, // unassigned - /* 0x8c */ kKeyNone, // unassigned - /* 0x8d */ kKeyNone, // unassigned - /* 0x8e */ kKeyNone, // unassigned - /* 0x8f */ kKeyNone, // unassigned - /* 0x90 */ kKeyNumLock, // VK_NUMLOCK - /* 0x91 */ kKeyScrollLock, // VK_SCROLL - /* 0x92 */ kKeyNone, // unassigned - /* 0x93 */ kKeyNone, // unassigned - /* 0x94 */ kKeyNone, // unassigned - /* 0x95 */ kKeyNone, // unassigned - /* 0x96 */ kKeyNone, // unassigned - /* 0x97 */ kKeyNone, // unassigned - /* 0x98 */ kKeyNone, // unassigned - /* 0x99 */ kKeyNone, // unassigned - /* 0x9a */ kKeyNone, // unassigned - /* 0x9b */ kKeyNone, // unassigned - /* 0x9c */ kKeyNone, // unassigned - /* 0x9d */ kKeyNone, // unassigned - /* 0x9e */ kKeyNone, // unassigned - /* 0x9f */ kKeyNone, // unassigned - /* 0xa0 */ kKeyShift_L, // VK_LSHIFT - /* 0xa1 */ kKeyShift_R, // VK_RSHIFT - /* 0xa2 */ kKeyControl_L, // VK_LCONTROL - /* 0xa3 */ kKeyControl_R, // VK_RCONTROL - /* 0xa4 */ kKeyAlt_L, // VK_LMENU - /* 0xa5 */ kKeyAlt_R, // VK_RMENU - /* 0xa6 */ kKeyNone, // unassigned - /* 0xa7 */ kKeyNone, // unassigned - /* 0xa8 */ kKeyNone, // unassigned - /* 0xa9 */ kKeyNone, // unassigned - /* 0xaa */ kKeyNone, // unassigned - /* 0xab */ kKeyNone, // unassigned - /* 0xac */ kKeyNone, // unassigned - /* 0xad */ kKeyNone, // unassigned - /* 0xae */ kKeyNone, // unassigned - /* 0xaf */ kKeyNone, // unassigned - /* 0xb0 */ kKeyNone, // unassigned - /* 0xb1 */ kKeyNone, // unassigned - /* 0xb2 */ kKeyNone, // unassigned - /* 0xb3 */ kKeyNone, // unassigned - /* 0xb4 */ kKeyNone, // unassigned - /* 0xb5 */ kKeyNone, // unassigned - /* 0xb6 */ kKeyNone, // unassigned - /* 0xb7 */ kKeyNone, // unassigned - /* 0xb8 */ kKeyNone, // unassigned - /* 0xb9 */ kKeyNone, // unassigned - /* 0xba */ kKeyNone, // OEM specific - /* 0xbb */ kKeyNone, // OEM specific - /* 0xbc */ kKeyNone, // OEM specific - /* 0xbd */ kKeyNone, // OEM specific - /* 0xbe */ kKeyNone, // OEM specific - /* 0xbf */ kKeyNone, // OEM specific - /* 0xc0 */ kKeyNone, // OEM specific - /* 0xc1 */ kKeyNone, // unassigned - /* 0xc2 */ kKeyNone, // unassigned - /* 0xc3 */ kKeyNone, // unassigned - /* 0xc4 */ kKeyNone, // unassigned - /* 0xc5 */ kKeyNone, // unassigned - /* 0xc6 */ kKeyNone, // unassigned - /* 0xc7 */ kKeyNone, // unassigned - /* 0xc8 */ kKeyNone, // unassigned - /* 0xc9 */ kKeyNone, // unassigned - /* 0xca */ kKeyNone, // unassigned - /* 0xcb */ kKeyNone, // unassigned - /* 0xcc */ kKeyNone, // unassigned - /* 0xcd */ kKeyNone, // unassigned - /* 0xce */ kKeyNone, // unassigned - /* 0xcf */ kKeyNone, // unassigned - /* 0xd0 */ kKeyNone, // unassigned - /* 0xd1 */ kKeyNone, // unassigned - /* 0xd2 */ kKeyNone, // unassigned - /* 0xd3 */ kKeyNone, // unassigned - /* 0xd4 */ kKeyNone, // unassigned - /* 0xd5 */ kKeyNone, // unassigned - /* 0xd6 */ kKeyNone, // unassigned - /* 0xd7 */ kKeyNone, // unassigned - /* 0xd8 */ kKeyNone, // unassigned - /* 0xd9 */ kKeyNone, // unassigned - /* 0xda */ kKeyNone, // unassigned - /* 0xdb */ kKeyNone, // OEM specific - /* 0xdc */ kKeyNone, // OEM specific - /* 0xdd */ kKeyNone, // OEM specific - /* 0xde */ kKeyNone, // OEM specific - /* 0xdf */ kKeyNone, // OEM specific - /* 0xe0 */ kKeyNone, // OEM specific - /* 0xe1 */ kKeyNone, // OEM specific - /* 0xe2 */ kKeyNone, // OEM specific - /* 0xe3 */ kKeyNone, // OEM specific - /* 0xe4 */ kKeyNone, // OEM specific - /* 0xe5 */ kKeyNone, // unassigned - /* 0xe6 */ kKeyNone, // OEM specific - /* 0xe7 */ kKeyNone, // unassigned - /* 0xe8 */ kKeyNone, // unassigned - /* 0xe9 */ kKeyNone, // OEM specific - /* 0xea */ kKeyNone, // OEM specific - /* 0xeb */ kKeyNone, // OEM specific - /* 0xec */ kKeyNone, // OEM specific - /* 0xed */ kKeyNone, // OEM specific - /* 0xee */ kKeyNone, // OEM specific - /* 0xef */ kKeyNone, // OEM specific - /* 0xf0 */ kKeyNone, // OEM specific - /* 0xf1 */ kKeyNone, // OEM specific - /* 0xf2 */ kKeyNone, // OEM specific - /* 0xf3 */ kKeyNone, // OEM specific - /* 0xf4 */ kKeyNone, // OEM specific - /* 0xf5 */ kKeyNone, // OEM specific - /* 0xf6 */ kKeyNone, // VK_ATTN - /* 0xf7 */ kKeyNone, // VK_CRSEL - /* 0xf8 */ kKeyNone, // VK_EXSEL - /* 0xf9 */ kKeyNone, // VK_EREOF - /* 0xfa */ kKeyNone, // VK_PLAY - /* 0xfb */ kKeyNone, // VK_ZOOM - /* 0xfc */ kKeyNone, // reserved - /* 0xfd */ kKeyNone, // VK_PA1 - /* 0xfe */ kKeyNone, // VK_OEM_CLEAR - /* 0xff */ kKeyNone // reserved + /* 0x00 */ kKeyNone, kKeyNone, // reserved + /* 0x01 */ kKeyNone, kKeyNone, // VK_LBUTTON + /* 0x02 */ kKeyNone, kKeyNone, // VK_RBUTTON + /* 0x03 */ kKeyNone, kKeyBreak, // VK_CANCEL + /* 0x04 */ kKeyNone, kKeyNone, // VK_MBUTTON + /* 0x05 */ kKeyNone, kKeyNone, // undefined + /* 0x06 */ kKeyNone, kKeyNone, // undefined + /* 0x07 */ kKeyNone, kKeyNone, // undefined + /* 0x08 */ kKeyBackSpace, kKeyNone, // VK_BACK + /* 0x09 */ kKeyTab, kKeyNone, // VK_TAB + /* 0x0a */ kKeyNone, kKeyNone, // undefined + /* 0x0b */ kKeyNone, kKeyNone, // undefined + /* 0x0c */ kKeyClear, kKeyClear, // VK_CLEAR + /* 0x0d */ kKeyReturn, kKeyKP_Enter, // VK_RETURN + /* 0x0e */ kKeyNone, kKeyNone, // undefined + /* 0x0f */ kKeyNone, kKeyNone, // undefined + /* 0x10 */ kKeyShift_L, kKeyShift_R, // VK_SHIFT + /* 0x11 */ kKeyControl_L, kKeyControl_R, // VK_CONTROL + /* 0x12 */ kKeyAlt_L, kKeyAlt_R, // VK_MENU + /* 0x13 */ kKeyPause, kKeyNone, // VK_PAUSE + /* 0x14 */ kKeyCapsLock, kKeyNone, // VK_CAPITAL + /* 0x15 */ kKeyNone, kKeyNone, // VK_KANA + /* 0x16 */ kKeyNone, kKeyNone, // VK_HANGUL + /* 0x17 */ kKeyNone, kKeyNone, // VK_JUNJA + /* 0x18 */ kKeyNone, kKeyNone, // VK_FINAL + /* 0x19 */ kKeyNone, kKeyNone, // VK_KANJI + /* 0x1a */ kKeyNone, kKeyNone, // undefined + /* 0x1b */ kKeyEscape, kKeyNone, // VK_ESCAPE + /* 0x1c */ kKeyNone, kKeyNone, // VK_CONVERT + /* 0x1d */ kKeyNone, kKeyNone, // VK_NONCONVERT + /* 0x1e */ kKeyNone, kKeyNone, // VK_ACCEPT + /* 0x1f */ kKeyNone, kKeyNone, // VK_MODECHANGE + /* 0x20 */ 0x0020, kKeyNone, // VK_SPACE + /* 0x21 */ kKeyKP_PageUp, kKeyPageUp, // VK_PRIOR + /* 0x22 */ kKeyKP_PageDown, kKeyPageDown, // VK_NEXT + /* 0x23 */ kKeyKP_End, kKeyEnd, // VK_END + /* 0x24 */ kKeyKP_Home, kKeyHome, // VK_HOME + /* 0x25 */ kKeyKP_Left, kKeyLeft, // VK_LEFT + /* 0x26 */ kKeyKP_Up, kKeyUp, // VK_UP + /* 0x27 */ kKeyKP_Right, kKeyRight, // VK_RIGHT + /* 0x28 */ kKeyKP_Down, kKeyDown, // VK_DOWN + /* 0x29 */ kKeySelect, kKeySelect, // VK_SELECT + /* 0x2a */ kKeyNone, kKeyNone, // VK_PRINT + /* 0x2b */ kKeyExecute, kKeyExecute, // VK_EXECUTE + /* 0x2c */ kKeyPrint, kKeyPrint, // VK_SNAPSHOT + /* 0x2d */ kKeyKP_Insert, kKeyInsert, // VK_INSERT + /* 0x2e */ kKeyKP_Delete, kKeyDelete, // VK_DELETE + /* 0x2f */ kKeyHelp, kKeyHelp, // VK_HELP + /* 0x30 */ kKeyNone, kKeyNone, // VK_0 + /* 0x31 */ kKeyNone, kKeyNone, // VK_1 + /* 0x32 */ kKeyNone, kKeyNone, // VK_2 + /* 0x33 */ kKeyNone, kKeyNone, // VK_3 + /* 0x34 */ kKeyNone, kKeyNone, // VK_4 + /* 0x35 */ kKeyNone, kKeyNone, // VK_5 + /* 0x36 */ kKeyNone, kKeyNone, // VK_6 + /* 0x37 */ kKeyNone, kKeyNone, // VK_7 + /* 0x38 */ kKeyNone, kKeyNone, // VK_8 + /* 0x39 */ kKeyNone, kKeyNone, // VK_9 + /* 0x3a */ kKeyNone, kKeyNone, // undefined + /* 0x3b */ kKeyNone, kKeyNone, // undefined + /* 0x3c */ kKeyNone, kKeyNone, // undefined + /* 0x3d */ kKeyNone, kKeyNone, // undefined + /* 0x3e */ kKeyNone, kKeyNone, // undefined + /* 0x3f */ kKeyNone, kKeyNone, // undefined + /* 0x40 */ kKeyNone, kKeyNone, // undefined + /* 0x41 */ kKeyNone, kKeyNone, // VK_A + /* 0x42 */ kKeyNone, kKeyNone, // VK_B + /* 0x43 */ kKeyNone, kKeyNone, // VK_C + /* 0x44 */ kKeyNone, kKeyNone, // VK_D + /* 0x45 */ kKeyNone, kKeyNone, // VK_E + /* 0x46 */ kKeyNone, kKeyNone, // VK_F + /* 0x47 */ kKeyNone, kKeyNone, // VK_G + /* 0x48 */ kKeyNone, kKeyNone, // VK_H + /* 0x49 */ kKeyNone, kKeyNone, // VK_I + /* 0x4a */ kKeyNone, kKeyNone, // VK_J + /* 0x4b */ kKeyNone, kKeyNone, // VK_K + /* 0x4c */ kKeyNone, kKeyNone, // VK_L + /* 0x4d */ kKeyNone, kKeyNone, // VK_M + /* 0x4e */ kKeyNone, kKeyNone, // VK_N + /* 0x4f */ kKeyNone, kKeyNone, // VK_O + /* 0x50 */ kKeyNone, kKeyNone, // VK_P + /* 0x51 */ kKeyNone, kKeyNone, // VK_Q + /* 0x52 */ kKeyNone, kKeyNone, // VK_R + /* 0x53 */ kKeyNone, kKeyNone, // VK_S + /* 0x54 */ kKeyNone, kKeyNone, // VK_T + /* 0x55 */ kKeyNone, kKeyNone, // VK_U + /* 0x56 */ kKeyNone, kKeyNone, // VK_V + /* 0x57 */ kKeyNone, kKeyNone, // VK_W + /* 0x58 */ kKeyNone, kKeyNone, // VK_X + /* 0x59 */ kKeyNone, kKeyNone, // VK_Y + /* 0x5a */ kKeyNone, kKeyNone, // VK_Z + /* 0x5b */ kKeyNone, kKeyMeta_L, // VK_LWIN + /* 0x5c */ kKeyNone, kKeyMeta_R, // VK_RWIN + /* 0x5d */ kKeyMenu, kKeyMenu, // VK_APPS + /* 0x5e */ kKeyNone, kKeyNone, // undefined + /* 0x5f */ kKeyNone, kKeyNone, // undefined + /* 0x60 */ kKeyKP_0, kKeyNone, // VK_NUMPAD0 + /* 0x61 */ kKeyKP_1, kKeyNone, // VK_NUMPAD1 + /* 0x62 */ kKeyKP_2, kKeyNone, // VK_NUMPAD2 + /* 0x63 */ kKeyKP_3, kKeyNone, // VK_NUMPAD3 + /* 0x64 */ kKeyKP_4, kKeyNone, // VK_NUMPAD4 + /* 0x65 */ kKeyKP_5, kKeyNone, // VK_NUMPAD5 + /* 0x66 */ kKeyKP_6, kKeyNone, // VK_NUMPAD6 + /* 0x67 */ kKeyKP_7, kKeyNone, // VK_NUMPAD7 + /* 0x68 */ kKeyKP_8, kKeyNone, // VK_NUMPAD8 + /* 0x69 */ kKeyKP_9, kKeyNone, // VK_NUMPAD9 + /* 0x6a */ kKeyKP_Multiply, kKeyNone, // VK_MULTIPLY + /* 0x6b */ kKeyKP_Add, kKeyNone, // VK_ADD + /* 0x6c */ kKeyKP_Separator,kKeyKP_Separator,// VK_SEPARATOR + /* 0x6d */ kKeyKP_Subtract, kKeyNone, // VK_SUBTRACT + /* 0x6e */ kKeyKP_Decimal, kKeyNone, // VK_DECIMAL + /* 0x6f */ kKeyNone, kKeyKP_Divide, // VK_DIVIDE + /* 0x70 */ kKeyF1, kKeyNone, // VK_F1 + /* 0x71 */ kKeyF2, kKeyNone, // VK_F2 + /* 0x72 */ kKeyF3, kKeyNone, // VK_F3 + /* 0x73 */ kKeyF4, kKeyNone, // VK_F4 + /* 0x74 */ kKeyF5, kKeyNone, // VK_F5 + /* 0x75 */ kKeyF6, kKeyNone, // VK_F6 + /* 0x76 */ kKeyF7, kKeyNone, // VK_F7 + /* 0x77 */ kKeyF8, kKeyNone, // VK_F8 + /* 0x78 */ kKeyF9, kKeyNone, // VK_F9 + /* 0x79 */ kKeyF10, kKeyNone, // VK_F10 + /* 0x7a */ kKeyF11, kKeyNone, // VK_F11 + /* 0x7b */ kKeyF12, kKeyNone, // VK_F12 + /* 0x7c */ kKeyF13, kKeyF13, // VK_F13 + /* 0x7d */ kKeyF14, kKeyF14, // VK_F14 + /* 0x7e */ kKeyF15, kKeyF15, // VK_F15 + /* 0x7f */ kKeyF16, kKeyF16, // VK_F16 + /* 0x80 */ kKeyF17, kKeyF17, // VK_F17 + /* 0x81 */ kKeyF18, kKeyF18, // VK_F18 + /* 0x82 */ kKeyF19, kKeyF19, // VK_F19 + /* 0x83 */ kKeyF20, kKeyF20, // VK_F20 + /* 0x84 */ kKeyF21, kKeyF21, // VK_F21 + /* 0x85 */ kKeyF22, kKeyF22, // VK_F22 + /* 0x86 */ kKeyF23, kKeyF23, // VK_F23 + /* 0x87 */ kKeyF24, kKeyF24, // VK_F24 + /* 0x88 */ kKeyNone, kKeyNone, // unassigned + /* 0x89 */ kKeyNone, kKeyNone, // unassigned + /* 0x8a */ kKeyNone, kKeyNone, // unassigned + /* 0x8b */ kKeyNone, kKeyNone, // unassigned + /* 0x8c */ kKeyNone, kKeyNone, // unassigned + /* 0x8d */ kKeyNone, kKeyNone, // unassigned + /* 0x8e */ kKeyNone, kKeyNone, // unassigned + /* 0x8f */ kKeyNone, kKeyNone, // unassigned + /* 0x90 */ kKeyNumLock, kKeyNumLock, // VK_NUMLOCK + /* 0x91 */ kKeyScrollLock, kKeyNone, // VK_SCROLL + /* 0x92 */ kKeyNone, kKeyNone, // unassigned + /* 0x93 */ kKeyNone, kKeyNone, // unassigned + /* 0x94 */ kKeyNone, kKeyNone, // unassigned + /* 0x95 */ kKeyNone, kKeyNone, // unassigned + /* 0x96 */ kKeyNone, kKeyNone, // unassigned + /* 0x97 */ kKeyNone, kKeyNone, // unassigned + /* 0x98 */ kKeyNone, kKeyNone, // unassigned + /* 0x99 */ kKeyNone, kKeyNone, // unassigned + /* 0x9a */ kKeyNone, kKeyNone, // unassigned + /* 0x9b */ kKeyNone, kKeyNone, // unassigned + /* 0x9c */ kKeyNone, kKeyNone, // unassigned + /* 0x9d */ kKeyNone, kKeyNone, // unassigned + /* 0x9e */ kKeyNone, kKeyNone, // unassigned + /* 0x9f */ kKeyNone, kKeyNone, // unassigned + /* 0xa0 */ kKeyShift_L, kKeyShift_L, // VK_LSHIFT + /* 0xa1 */ kKeyShift_R, kKeyShift_R, // VK_RSHIFT + /* 0xa2 */ kKeyControl_L, kKeyControl_L, // VK_LCONTROL + /* 0xa3 */ kKeyControl_R, kKeyControl_R, // VK_RCONTROL + /* 0xa4 */ kKeyAlt_L, kKeyAlt_L, // VK_LMENU + /* 0xa5 */ kKeyAlt_R, kKeyAlt_R, // VK_RMENU + /* 0xa6 */ kKeyNone, kKeyNone, // unassigned + /* 0xa7 */ kKeyNone, kKeyNone, // unassigned + /* 0xa8 */ kKeyNone, kKeyNone, // unassigned + /* 0xa9 */ kKeyNone, kKeyNone, // unassigned + /* 0xaa */ kKeyNone, kKeyNone, // unassigned + /* 0xab */ kKeyNone, kKeyNone, // unassigned + /* 0xac */ kKeyNone, kKeyNone, // unassigned + /* 0xad */ kKeyNone, kKeyNone, // unassigned + /* 0xae */ kKeyNone, kKeyNone, // unassigned + /* 0xaf */ kKeyNone, kKeyNone, // unassigned + /* 0xb0 */ kKeyNone, kKeyNone, // unassigned + /* 0xb1 */ kKeyNone, kKeyNone, // unassigned + /* 0xb2 */ kKeyNone, kKeyNone, // unassigned + /* 0xb3 */ kKeyNone, kKeyNone, // unassigned + /* 0xb4 */ kKeyNone, kKeyNone, // unassigned + /* 0xb5 */ kKeyNone, kKeyNone, // unassigned + /* 0xb6 */ kKeyNone, kKeyNone, // unassigned + /* 0xb7 */ kKeyNone, kKeyNone, // unassigned + /* 0xb8 */ kKeyNone, kKeyNone, // unassigned + /* 0xb9 */ kKeyNone, kKeyNone, // unassigned + /* 0xba */ kKeyNone, kKeyNone, // OEM specific + /* 0xbb */ kKeyNone, kKeyNone, // OEM specific + /* 0xbc */ kKeyNone, kKeyNone, // OEM specific + /* 0xbd */ kKeyNone, kKeyNone, // OEM specific + /* 0xbe */ kKeyNone, kKeyNone, // OEM specific + /* 0xbf */ kKeyNone, kKeyNone, // OEM specific + /* 0xc0 */ kKeyNone, kKeyNone, // OEM specific + /* 0xc1 */ kKeyNone, kKeyNone, // unassigned + /* 0xc2 */ kKeyNone, kKeyNone, // unassigned + /* 0xc3 */ kKeyNone, kKeyNone, // unassigned + /* 0xc4 */ kKeyNone, kKeyNone, // unassigned + /* 0xc5 */ kKeyNone, kKeyNone, // unassigned + /* 0xc6 */ kKeyNone, kKeyNone, // unassigned + /* 0xc7 */ kKeyNone, kKeyNone, // unassigned + /* 0xc8 */ kKeyNone, kKeyNone, // unassigned + /* 0xc9 */ kKeyNone, kKeyNone, // unassigned + /* 0xca */ kKeyNone, kKeyNone, // unassigned + /* 0xcb */ kKeyNone, kKeyNone, // unassigned + /* 0xcc */ kKeyNone, kKeyNone, // unassigned + /* 0xcd */ kKeyNone, kKeyNone, // unassigned + /* 0xce */ kKeyNone, kKeyNone, // unassigned + /* 0xcf */ kKeyNone, kKeyNone, // unassigned + /* 0xd0 */ kKeyNone, kKeyNone, // unassigned + /* 0xd1 */ kKeyNone, kKeyNone, // unassigned + /* 0xd2 */ kKeyNone, kKeyNone, // unassigned + /* 0xd3 */ kKeyNone, kKeyNone, // unassigned + /* 0xd4 */ kKeyNone, kKeyNone, // unassigned + /* 0xd5 */ kKeyNone, kKeyNone, // unassigned + /* 0xd6 */ kKeyNone, kKeyNone, // unassigned + /* 0xd7 */ kKeyNone, kKeyNone, // unassigned + /* 0xd8 */ kKeyNone, kKeyNone, // unassigned + /* 0xd9 */ kKeyNone, kKeyNone, // unassigned + /* 0xda */ kKeyNone, kKeyNone, // unassigned + /* 0xdb */ kKeyNone, kKeyNone, // OEM specific + /* 0xdc */ kKeyNone, kKeyNone, // OEM specific + /* 0xdd */ kKeyNone, kKeyNone, // OEM specific + /* 0xde */ kKeyNone, kKeyNone, // OEM specific + /* 0xdf */ kKeyNone, kKeyNone, // OEM specific + /* 0xe0 */ kKeyNone, kKeyNone, // OEM specific + /* 0xe1 */ kKeyNone, kKeyNone, // OEM specific + /* 0xe2 */ kKeyNone, kKeyNone, // OEM specific + /* 0xe3 */ kKeyNone, kKeyNone, // OEM specific + /* 0xe4 */ kKeyNone, kKeyNone, // OEM specific + /* 0xe5 */ kKeyNone, kKeyNone, // unassigned + /* 0xe6 */ kKeyNone, kKeyNone, // OEM specific + /* 0xe7 */ kKeyNone, kKeyNone, // unassigned + /* 0xe8 */ kKeyNone, kKeyNone, // unassigned + /* 0xe9 */ kKeyNone, kKeyNone, // OEM specific + /* 0xea */ kKeyNone, kKeyNone, // OEM specific + /* 0xeb */ kKeyNone, kKeyNone, // OEM specific + /* 0xec */ kKeyNone, kKeyNone, // OEM specific + /* 0xed */ kKeyNone, kKeyNone, // OEM specific + /* 0xee */ kKeyNone, kKeyNone, // OEM specific + /* 0xef */ kKeyNone, kKeyNone, // OEM specific + /* 0xf0 */ kKeyNone, kKeyNone, // OEM specific + /* 0xf1 */ kKeyNone, kKeyNone, // OEM specific + /* 0xf2 */ kKeyNone, kKeyNone, // OEM specific + /* 0xf3 */ kKeyNone, kKeyNone, // OEM specific + /* 0xf4 */ kKeyNone, kKeyNone, // OEM specific + /* 0xf5 */ kKeyNone, kKeyNone, // OEM specific + /* 0xf6 */ kKeyNone, kKeyNone, // VK_ATTN + /* 0xf7 */ kKeyNone, kKeyNone, // VK_CRSEL + /* 0xf8 */ kKeyNone, kKeyNone, // VK_EXSEL + /* 0xf9 */ kKeyNone, kKeyNone, // VK_EREOF + /* 0xfa */ kKeyNone, kKeyNone, // VK_PLAY + /* 0xfb */ kKeyNone, kKeyNone, // VK_ZOOM + /* 0xfc */ kKeyNone, kKeyNone, // reserved + /* 0xfd */ kKeyNone, kKeyNone, // VK_PA1 + /* 0xfe */ kKeyNone, kKeyNone, // VK_OEM_CLEAR + /* 0xff */ kKeyNone, kKeyNone // reserved }; KeyID @@ -918,68 +920,22 @@ CMSWindowsPrimaryScreen::mapKey( if ((m_keys[VK_SCROLL] & 0x01) != 0) { mask |= KeyModifierScrollLock; } + if ((mask & (KeyModifierControl | KeyModifierAlt)) == + (KeyModifierControl | KeyModifierAlt)) { + // ctrl+alt => AltGr on windows + mask |= KeyModifierModeSwitch; + mask &= ~(KeyModifierControl | KeyModifierAlt); + } *maskOut = mask; log((CLOG_DEBUG2 "key in vk=%d info=0x%08x mask=0x%04x", vkCode, info, mask)); - // get the scan code - UINT scanCode = static_cast((info & 0xff0000) >> 16); - - // convert virtual key to one that distinguishes between left and - // right for keys that have left/right versions. known scan codes - // that don't have left/right versions are passed through unchanged. - // unknown scan codes return 0. - UINT vkCode2 = MapVirtualKey(scanCode, 3); - - // work around bug Q72583 (bad num pad conversion in MapVirtualKey()) - if (vkCode >= VK_NUMPAD0 && vkCode <= VK_DIVIDE) { - vkCode2 = vkCode; - } - - // MapVirtualKey() appears to map VK_LWIN, VK_RWIN, VK_APPS to - // some other meaningless virtual key. work around that bug. - else if (vkCode >= VK_LWIN && vkCode <= VK_APPS) { - vkCode2 = vkCode; - } - - // if the original vkCode is VK_SNAPSHOT then use it. oddly enough, - // some keyboards use the same scan code for keypad multiply and - // print screen. the difference is that the latter has the extended - // key flag set. but MapVirtualKey() doesn't seem capable of using - // that flag. - else if (vkCode == VK_SNAPSHOT) { - vkCode2 = vkCode; - } - - // if MapVirtualKey failed then use original virtual key - else if (vkCode2 == 0) { - vkCode2 = vkCode; - } - - // sadly, win32 will not distinguish between the left and right - // control and alt keys using the above function. however, we - // can check for those: if bit 24 of info is set then the key - // is a "extended" key, such as the right control and right alt - // keys. - if ((info & 0x1000000) != 0) { - switch (vkCode2) { - case VK_CONTROL: - case VK_LCONTROL: - vkCode2 = VK_RCONTROL; - break; - - case VK_MENU: - case VK_LMENU: - vkCode2 = VK_RMENU; - break; - } - } - - // use left/right distinguishing virtual key - vkCode = vkCode2; - log((CLOG_DEBUG1 "key vk=%d scan=%d", vkCode, scanCode)); + // get the scan code and the extended keyboard flag + UINT scanCode = static_cast((info & 0x00ff0000u) >> 16); + int extended = ((info & 0x01000000) == 0) ? 0 : 1; + log((CLOG_DEBUG1 "key vk=%d ext=%d scan=%d", vkCode, extended, scanCode)); // handle some keys via table lookup - KeyID id = g_virtualKey[vkCode]; + KeyID id = g_virtualKey[vkCode][extended]; if (id != kKeyNone) { return id; } @@ -989,17 +945,19 @@ CMSWindowsPrimaryScreen::mapKey( return kKeyMultiKey; } - // ToAscii() maps ctrl+letter to the corresponding control code - // and ctrl+backspace to delete. if we've got a control code or - // delete then do ToAscii() again but without the control state. - // ToAscii() interprets the control modifier state which we don't - // want. so save the control state then clear it. - BYTE lControl = m_keys[VK_LCONTROL]; - BYTE rControl = m_keys[VK_RCONTROL]; - BYTE control = m_keys[VK_CONTROL]; - m_keys[VK_LCONTROL] = 0; - m_keys[VK_RCONTROL] = 0; - m_keys[VK_CONTROL] = 0; + // save the control state then clear it. ToAscii() maps ctrl+letter + // to the corresponding control code and ctrl+backspace to delete. + // we don't want that translation so we clear the control modifier + // state. however, if we want to simulate AltGr (which is ctrl+alt) + // then we must not clear it. + BYTE lControl = m_keys[VK_LCONTROL]; + BYTE rControl = m_keys[VK_RCONTROL]; + BYTE control = m_keys[VK_CONTROL]; + if ((mask & KeyModifierModeSwitch) == 0) { + m_keys[VK_LCONTROL] = 0; + m_keys[VK_RCONTROL] = 0; + m_keys[VK_CONTROL] = 0; + } // convert to ascii // FIXME -- support unicode @@ -1092,18 +1050,18 @@ CMSWindowsPrimaryScreen::updateKeys() // we only care about the modifier key states. other keys and the // mouse buttons should be up. - m_keys[VK_LSHIFT] = static_cast(GetKeyState(VK_LSHIFT)); - m_keys[VK_RSHIFT] = static_cast(GetKeyState(VK_RSHIFT)); - m_keys[VK_SHIFT] = static_cast(GetKeyState(VK_SHIFT)); - m_keys[VK_LCONTROL] = static_cast(GetKeyState(VK_LCONTROL)); - m_keys[VK_RCONTROL] = static_cast(GetKeyState(VK_RCONTROL)); - m_keys[VK_CONTROL] = static_cast(GetKeyState(VK_CONTROL)); - m_keys[VK_LMENU] = static_cast(GetKeyState(VK_LMENU)); - m_keys[VK_RMENU] = static_cast(GetKeyState(VK_RMENU)); - m_keys[VK_MENU] = static_cast(GetKeyState(VK_MENU)); - m_keys[VK_LWIN] = static_cast(GetKeyState(VK_LWIN)); - m_keys[VK_RWIN] = static_cast(GetKeyState(VK_RWIN)); - m_keys[VK_APPS] = static_cast(GetKeyState(VK_APPS)); + m_keys[VK_LSHIFT] = static_cast(GetKeyState(VK_LSHIFT) & 0x80); + m_keys[VK_RSHIFT] = static_cast(GetKeyState(VK_RSHIFT) & 0x80); + m_keys[VK_SHIFT] = static_cast(GetKeyState(VK_SHIFT) & 0x80); + m_keys[VK_LCONTROL] = static_cast(GetKeyState(VK_LCONTROL) & 0x80); + m_keys[VK_RCONTROL] = static_cast(GetKeyState(VK_RCONTROL) & 0x80); + m_keys[VK_CONTROL] = static_cast(GetKeyState(VK_CONTROL) & 0x80); + m_keys[VK_LMENU] = static_cast(GetKeyState(VK_LMENU) & 0x80); + m_keys[VK_RMENU] = static_cast(GetKeyState(VK_RMENU) & 0x80); + m_keys[VK_MENU] = static_cast(GetKeyState(VK_MENU) & 0x80); + m_keys[VK_LWIN] = static_cast(GetKeyState(VK_LWIN) & 0x80); + m_keys[VK_RWIN] = static_cast(GetKeyState(VK_RWIN) & 0x80); + m_keys[VK_APPS] = static_cast(GetKeyState(VK_APPS) & 0x80); m_keys[VK_CAPITAL] = static_cast(GetKeyState(VK_CAPITAL)); m_keys[VK_NUMLOCK] = static_cast(GetKeyState(VK_NUMLOCK)); m_keys[VK_SCROLL] = static_cast(GetKeyState(VK_SCROLL));