summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAnton Sharonov <anton.sharonov@gmail.com>2022-07-26 21:26:18 +0100
committerBram Moolenaar <Bram@vim.org>2022-07-26 21:26:18 +0100
commit3f0266739db7d27cb7f03f9d131114fb0af3df71 (patch)
treee6e68c378dbacee50c2b6d71738f2d8af0f872aa
parent6791adca53981666f0cf23e264e102b795224044 (diff)
downloadvim-git-3f0266739db7d27cb7f03f9d131114fb0af3df71.tar.gz
patch 9.0.0087: MS-Windows: CTRL-[ on Belgian keyboard does not work like Escv9.0.0087
Problem: MS-Windows: CTRL-[ on Belgian keyboard does not work like Esc. Solution: Figure out what the key code means. (Anton Sharonov, closes #10687, closes #10454)
-rw-r--r--src/gui_w32.c98
-rw-r--r--src/version.c2
2 files changed, 90 insertions, 10 deletions
diff --git a/src/gui_w32.c b/src/gui_w32.c
index 472cebf73..397dd7f90 100644
--- a/src/gui_w32.c
+++ b/src/gui_w32.c
@@ -29,6 +29,12 @@
# include "gui_dwrite.h"
#endif
+// values for "dead_key"
+#define DEAD_KEY_OFF 0 // no dead key
+#define DEAD_KEY_SET_DEFAULT 1 // dead key pressed
+#define DEAD_KEY_TRANSIENT_IN_ON_CHAR 2 // wait for next key press
+#define DEAD_KEY_SKIP_ON_CHAR 3 // skip next _OnChar()
+
#if defined(FEAT_DIRECTX)
static DWriteContext *s_dwc = NULL;
static int s_directx_enabled = 0;
@@ -533,7 +539,7 @@ static int s_y_pending;
static UINT s_kFlags_pending;
static UINT_PTR s_wait_timer = 0; // Timer for get char from user
static int s_timed_out = FALSE;
-static int dead_key = 0; // 0: no dead key, 1: dead key pressed
+static int dead_key = DEAD_KEY_OFF;
static UINT surrogate_pending_ch = 0; // 0: no surrogate pending,
// else a high surrogate
@@ -866,7 +872,13 @@ _OnChar(
int modifiers;
int ch = cch; // special keys are negative
- dead_key = 0;
+ if (dead_key == DEAD_KEY_SKIP_ON_CHAR)
+ return;
+
+ // keep DEAD_KEY_TRANSIENT_IN_ON_CHAR value for later handling in
+ // process_message()
+ if (dead_key != DEAD_KEY_TRANSIENT_IN_ON_CHAR)
+ dead_key = DEAD_KEY_OFF;
modifiers = get_active_modifiers();
@@ -912,7 +924,7 @@ _OnSysChar(
int modifiers;
int ch = cch; // special keys are negative
- dead_key = 0;
+ dead_key = DEAD_KEY_OFF;
// OK, we have a character key (given by ch) which was entered with the
// ALT key pressed. Eg, if the user presses Alt-A, then ch == 'A'. Note
@@ -1844,14 +1856,14 @@ gui_mch_draw_part_cursor(
* dead key's nominal character and re-post the original message.
*/
static void
-outputDeadKey_rePost(MSG originalMsg)
+outputDeadKey_rePost_Ex(MSG originalMsg, int dead_key2set)
{
static MSG deadCharExpel;
- if (!dead_key)
+ if (dead_key == DEAD_KEY_OFF)
return;
- dead_key = 0;
+ dead_key = dead_key2set;
// Make Windows generate the dead key's character
deadCharExpel.message = originalMsg.message;
@@ -1866,6 +1878,15 @@ outputDeadKey_rePost(MSG originalMsg)
}
/*
+ * Wrapper for outputDeadKey_rePost_Ex which always reset dead_key value.
+ */
+ static void
+outputDeadKey_rePost(MSG originalMsg)
+{
+ outputDeadKey_rePost_Ex(originalMsg, DEAD_KEY_OFF);
+}
+
+/*
* Process a single Windows message.
* If one is not available we hang until one is.
*/
@@ -1936,9 +1957,48 @@ process_message(void)
* for some reason TranslateMessage() do not trigger a call
* immediately to _OnChar() (or _OnSysChar()).
*/
- if (dead_key)
+
+ /*
+ * We are at the moment after WM_CHAR with DEAD_KEY_SKIP_ON_CHAR event
+ * was handled by _WndProc, this keypress we want to process normally
+ */
+ if (dead_key == DEAD_KEY_SKIP_ON_CHAR)
+ dead_key = DEAD_KEY_OFF;
+
+ if (dead_key != DEAD_KEY_OFF)
{
/*
+ * Expell the dead key pressed with Ctrl in a special way.
+ *
+ * After dead key was pressed with Ctrl in some cases, ESC was
+ * artificially injected and handled by _OnChar(), now we are
+ * dealing with completely new key press from the user. If we don't
+ * do anything, ToUnicode() call will interpret this vk+scan_code
+ * under influence of "dead-modifier". To prevent this we translate
+ * this message replacing current char from user with VK_SPACE,
+ * which will cause WM_CHAR with dead_key's character itself. Using
+ * DEAD_KEY_SKIP_ON_CHAR value of dead_char we force _OnChar() to
+ * ignore this one WM_CHAR event completely. Afterwards (due to
+ * usage of PostMessage), this procedure is scheduled to be called
+ * again with user char and on next entry we will clean
+ * DEAD_KEY_SKIP_ON_CHAR. We cannot use original
+ * outputDeadKey_rePost() since we do not wish to reset dead_key
+ * value.
+ */
+ if (dead_key == DEAD_KEY_TRANSIENT_IN_ON_CHAR)
+ {
+ outputDeadKey_rePost_Ex(msg,
+ /*dead_key2set=*/DEAD_KEY_SKIP_ON_CHAR);
+ return;
+ }
+
+ if (dead_key != DEAD_KEY_SET_DEFAULT)
+ {
+ // should never happen - is there a way to make ASSERT here?
+ return;
+ }
+
+ /*
* If a dead key was pressed and the user presses VK_SPACE,
* VK_BACK, or VK_ESCAPE it means that he actually wants to deal
* with the dead char now, so do nothing special and let Windows
@@ -1952,7 +2012,7 @@ process_message(void)
*/
if ((vk == VK_SPACE || vk == VK_BACK || vk == VK_ESCAPE))
{
- dead_key = 0;
+ dead_key = DEAD_KEY_OFF;
TranslateMessage(&msg);
return;
}
@@ -1995,7 +2055,7 @@ process_message(void)
* character output (such as a NUMPAD printable character or
* the TAB key, etc...).
*/
- if (dead_key && (special_keys[i].vim_code0 == 'K'
+ if (dead_key == DEAD_KEY_SET_DEFAULT && (special_keys[i].vim_code0 == 'K'
|| vk == VK_TAB || vk == CAR))
{
outputDeadKey_rePost(msg);
@@ -2081,10 +2141,28 @@ process_message(void)
// If this is a dead key ToUnicode returns a negative value.
len = ToUnicode(vk, scan_code, keyboard_state, ch, ARRAY_LENGTH(ch),
0);
- dead_key = len < 0;
+ if (len < 0)
+ dead_key = DEAD_KEY_SET_DEFAULT;
if (len <= 0)
+ {
+ if ( dead_key == DEAD_KEY_SET_DEFAULT
+ && (GetKeyState(VK_CONTROL) & 0x8000)
+ && ( (vk == 221 && scan_code == 26) // AZERTY CTRL+dead_circumflex
+ || (vk == 220 && scan_code == 41) // QWERTZ CTRL+dead_circumflex
+ )
+ )
+ {
+ // post WM_CHAR='[' - which will be interpreted with CTRL
+ // stil hold as ESC
+ PostMessageW(msg.hwnd, WM_CHAR, '[', msg.lParam);
+ // ask _OnChar() to not touch this state, wait for next key
+ // press and maintain knowledge that we are "poisoned" with
+ // "dead state"
+ dead_key = DEAD_KEY_TRANSIENT_IN_ON_CHAR;
+ }
return;
+ }
// Post the message as TranslateMessage would do.
if (msg.message == WM_KEYDOWN)
diff --git a/src/version.c b/src/version.c
index ead1e1541..75fe0edf9 100644
--- a/src/version.c
+++ b/src/version.c
@@ -736,6 +736,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
+ 87,
+/**/
86,
/**/
85,