+\f
+
+/* Equivalent of strerror for W32 error codes. */
+char *
+w32_strerror (int error_no)
+{
+ static char buf[500];
+ DWORD ret;
+
+ if (error_no == 0)
+ error_no = GetLastError ();
+
+ ret = FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM |
+ FORMAT_MESSAGE_IGNORE_INSERTS,
+ NULL,
+ error_no,
+ 0, /* choose most suitable language */
+ buf, sizeof (buf), NULL);
+
+ while (ret > 0 && (buf[ret - 1] == '\n' ||
+ buf[ret - 1] == '\r' ))
+ --ret;
+ buf[ret] = '\0';
+ if (!ret)
+ sprintf (buf, "w32 error %u", error_no);
+
+ return buf;
+}
+
+/* For convenience when debugging. */
+int
+w32_last_error (void)
+{
+ return GetLastError ();
+}
+
+/* Cache information describing the NT system for later use. */
+void
+cache_system_info (void)
+{
+ union
+ {
+ struct info
+ {
+ char major;
+ char minor;
+ short platform;
+ } info;
+ DWORD data;
+ } version;
+
+ /* Cache the version of the operating system. */
+ version.data = GetVersion ();
+ w32_major_version = version.info.major;
+ w32_minor_version = version.info.minor;
+
+ if (version.info.platform & 0x8000)
+ os_subtype = OS_9X;
+ else
+ os_subtype = OS_NT;
+
+ /* Cache page size, allocation unit, processor type, etc. */
+ GetSystemInfo (&sysinfo_cache);
+ syspage_mask = sysinfo_cache.dwPageSize - 1;
+
+ /* Cache os info. */
+ osinfo_cache.dwOSVersionInfoSize = sizeof (OSVERSIONINFO);
+ GetVersionEx (&osinfo_cache);
+
+ w32_build_number = osinfo_cache.dwBuildNumber;
+ if (os_subtype == OS_9X)
+ w32_build_number &= 0xffff;
+
+ w32_num_mouse_buttons = GetSystemMetrics (SM_CMOUSEBUTTONS);
+}
+
+#ifdef EMACSDEBUG
+void
+_DebPrint (const char *fmt, ...)
+{
+ char buf[1024];
+ va_list args;
+
+ va_start (args, fmt);
+ vsprintf (buf, fmt, args);
+ va_end (args);
+#if CYGWIN
+ fprintf (stderr, "%s", buf);
+#endif
+ OutputDebugString (buf);
+}
+#endif
+
+int
+w32_console_toggle_lock_key (int vk_code, Lisp_Object new_state)
+{
+ int cur_state = (GetKeyState (vk_code) & 1);
+
+ if (NILP (new_state)
+ || (NUMBERP (new_state)
+ && ((XUINT (new_state)) & 1) != cur_state))
+ {
+#ifdef WINDOWSNT
+ faked_key = vk_code;
+#endif /* WINDOWSNT */
+
+ keybd_event ((BYTE) vk_code,
+ (BYTE) MapVirtualKey (vk_code, 0),
+ KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
+ keybd_event ((BYTE) vk_code,
+ (BYTE) MapVirtualKey (vk_code, 0),
+ KEYEVENTF_EXTENDEDKEY | 0, 0);
+ keybd_event ((BYTE) vk_code,
+ (BYTE) MapVirtualKey (vk_code, 0),
+ KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
+ cur_state = !cur_state;
+ }
+
+ return cur_state;
+}
+
+/* Translate console modifiers to emacs modifiers.
+ German keyboard support (Kai Morgan Zeise 2/18/95). */
+int
+w32_kbd_mods_to_emacs (DWORD mods, WORD key)
+{
+ int retval = 0;
+
+ /* If we recognize right-alt and left-ctrl as AltGr, and it has been
+ pressed, first remove those modifiers. */
+ if (!NILP (Vw32_recognize_altgr)
+ && (mods & (RIGHT_ALT_PRESSED | LEFT_CTRL_PRESSED))
+ == (RIGHT_ALT_PRESSED | LEFT_CTRL_PRESSED))
+ mods &= ~ (RIGHT_ALT_PRESSED | LEFT_CTRL_PRESSED);
+
+ if (mods & (RIGHT_ALT_PRESSED | LEFT_ALT_PRESSED))
+ retval = ((NILP (Vw32_alt_is_meta)) ? alt_modifier : meta_modifier);
+
+ if (mods & (RIGHT_CTRL_PRESSED | LEFT_CTRL_PRESSED))
+ {
+ retval |= ctrl_modifier;
+ if ((mods & (RIGHT_CTRL_PRESSED | LEFT_CTRL_PRESSED))
+ == (RIGHT_CTRL_PRESSED | LEFT_CTRL_PRESSED))
+ retval |= meta_modifier;
+ }
+
+ if (mods & LEFT_WIN_PRESSED)
+ retval |= w32_key_to_modifier (VK_LWIN);
+ if (mods & RIGHT_WIN_PRESSED)
+ retval |= w32_key_to_modifier (VK_RWIN);
+ if (mods & APPS_PRESSED)
+ retval |= w32_key_to_modifier (VK_APPS);
+ if (mods & SCROLLLOCK_ON)
+ retval |= w32_key_to_modifier (VK_SCROLL);
+
+ /* Just in case someone wanted the original behavior, make it
+ optional by setting w32-capslock-is-shiftlock to t. */
+ if (NILP (Vw32_capslock_is_shiftlock)
+ /* Keys that should _not_ be affected by CapsLock. */
+ && ( (key == VK_BACK)
+ || (key == VK_TAB)
+ || (key == VK_CLEAR)
+ || (key == VK_RETURN)
+ || (key == VK_ESCAPE)
+ || ((key >= VK_SPACE) && (key <= VK_HELP))
+ || ((key >= VK_NUMPAD0) && (key <= VK_F24))
+ || ((key >= VK_NUMPAD_CLEAR) && (key <= VK_NUMPAD_DELETE))
+ ))
+ {
+ /* Only consider shift state. */
+ if ((mods & SHIFT_PRESSED) != 0)
+ retval |= shift_modifier;
+ }
+ else
+ {
+ /* Ignore CapsLock state if not enabled. */
+ if (NILP (Vw32_enable_caps_lock))
+ mods &= ~CAPSLOCK_ON;
+ if ((mods & (SHIFT_PRESSED | CAPSLOCK_ON)) != 0)
+ retval |= shift_modifier;
+ }
+
+ return retval;
+}
+
+/* The return code indicates key code size. cpID is the codepage to
+ use for translation to Unicode; -1 means use the current console
+ input codepage. */
+int
+w32_kbd_patch_key (KEY_EVENT_RECORD *event, int cpId)
+{
+ unsigned int key_code = event->wVirtualKeyCode;
+ unsigned int mods = event->dwControlKeyState;
+ BYTE keystate[256];
+ static BYTE ansi_code[4];
+ static int isdead = 0;
+
+ if (isdead == 2)
+ {
+ event->uChar.AsciiChar = ansi_code[2];
+ isdead = 0;
+ return 1;
+ }
+ if (event->uChar.AsciiChar != 0)
+ return 1;
+
+ memset (keystate, 0, sizeof (keystate));
+ keystate[key_code] = 0x80;
+ if (mods & SHIFT_PRESSED)
+ keystate[VK_SHIFT] = 0x80;
+ if (mods & CAPSLOCK_ON)
+ keystate[VK_CAPITAL] = 1;
+ /* If we recognize right-alt and left-ctrl as AltGr, set the key
+ states accordingly before invoking ToAscii. */
+ if (!NILP (Vw32_recognize_altgr)
+ && (mods & LEFT_CTRL_PRESSED) && (mods & RIGHT_ALT_PRESSED))
+ {
+ keystate[VK_CONTROL] = 0x80;
+ keystate[VK_LCONTROL] = 0x80;
+ keystate[VK_MENU] = 0x80;
+ keystate[VK_RMENU] = 0x80;
+ }
+
+#if 0
+ /* Because of an OS bug, ToAscii corrupts the stack when called to
+ convert a dead key in console mode on NT4. Unfortunately, trying
+ to check for dead keys using MapVirtualKey doesn't work either -
+ these functions apparently use internal information about keyboard
+ layout which doesn't get properly updated in console programs when
+ changing layout (though apparently it gets partly updated,
+ otherwise ToAscii wouldn't crash). */
+ if (is_dead_key (event->wVirtualKeyCode))
+ return 0;
+#endif
+
+ /* On NT, call ToUnicode instead and then convert to the current
+ console input codepage. */
+ if (os_subtype == OS_NT)
+ {
+ WCHAR buf[128];
+
+ isdead = ToUnicode (event->wVirtualKeyCode, event->wVirtualScanCode,
+ keystate, buf, 128, 0);
+ if (isdead > 0)
+ {
+ /* When we are called from the GUI message processing code,
+ we are passed the current keyboard codepage, a positive
+ number, to use below. */
+ if (cpId == -1)
+ cpId = GetConsoleCP ();
+
+ event->uChar.UnicodeChar = buf[isdead - 1];
+ isdead = WideCharToMultiByte (cpId, 0, buf, isdead,
+ ansi_code, 4, NULL, NULL);
+ }
+ else
+ isdead = 0;
+ }
+ else
+ {
+ isdead = ToAscii (event->wVirtualKeyCode, event->wVirtualScanCode,
+ keystate, (LPWORD) ansi_code, 0);
+ }
+
+ if (isdead == 0)
+ return 0;
+ event->uChar.AsciiChar = ansi_code[0];
+ return isdead;
+}
+
+
+void
+w32_sys_ring_bell (struct frame *f)
+{
+ if (sound_type == 0xFFFFFFFF)
+ {
+ Beep (666, 100);
+ }
+ else if (sound_type == MB_EMACS_SILENT)
+ {
+ /* Do nothing. */
+ }
+ else
+ MessageBeep (sound_type);
+}
+