summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authortrustable-code <krauter.simon@arcor.de>2018-04-13 13:55:54 +0200
committertrustable-code <krauter.simon@arcor.de>2018-04-13 13:55:54 +0200
commit9a44a3471e88f449ad02ac465ef5f5e21cd5218b (patch)
tree8bf6edfbbe46f20a066cc3ff33d42614b6f3e315
parenta4788573bcec06b0d9123359ce5905d26944e09e (diff)
downloadNiGui-9a44a3471e88f449ad02ac465ef5f5e21cd5218b.tar.gz
NiGui-9a44a3471e88f449ad02ac465ef5f5e21cd5218b.zip
Improve handling of dead keys
When you press the dead key "^" followed by space on a German keyboard, the applicaton receives the following two KeyDown events: 1. event.key = Key_Circumflex, event.character = "" 2. event.key = Key_Space, event.character = "^" Under Gtk this should work for all dead keys by using GtkIMContext. Under Windows it is implemented only for the scan code of the dead key "^" on a German keyboard.
-rwxr-xr-xsrc/nigui.nim105
-rwxr-xr-xsrc/nigui/private/gtk3/gtk3.nim3
-rwxr-xr-xsrc/nigui/private/gtk3/platform_impl.nim72
-rwxr-xr-xsrc/nigui/private/gtk3/platform_types1.nim4
-rwxr-xr-xsrc/nigui/private/windows/platform_impl.nim14
5 files changed, 113 insertions, 85 deletions
diff --git a/src/nigui.nim b/src/nigui.nim
index d0281b6..fef6fcc 100755
--- a/src/nigui.nim
+++ b/src/nigui.nim
@@ -68,59 +68,60 @@ type
Key* = enum
# Keys with same value than Unicode:
- Key_None = 0
- Key_Backspace = 8
- Key_Tab = 9
- Key_Return = 13
- Key_Escape = 27
- Key_Space = 32
- Key_Asterisk = 42
- Key_Plus = 43
- Key_Comma = 44
- Key_Minus = 45
- Key_Point = 46
- Key_Number0 = 48
- Key_Number1 = 49
- Key_Number2 = 50
- Key_Number3 = 51
- Key_Number4 = 52
- Key_Number5 = 53
- Key_Number6 = 54
- Key_Number7 = 55
- Key_Number8 = 56
- Key_Number9 = 57
- Key_A = 65
- Key_B = 66
- Key_C = 67
- Key_D = 68
- Key_E = 69
- Key_F = 70
- Key_G = 71
- Key_H = 72
- Key_I = 73
- Key_J = 74
- Key_K = 75
- Key_L = 76
- Key_M = 77
- Key_N = 78
- Key_O = 79
- Key_P = 80
- Key_Q = 81
- Key_R = 82
- Key_S = 83
- Key_T = 84
- Key_U = 85
- Key_V = 86
- Key_W = 87
- Key_X = 88
- Key_Y = 89
- Key_Z = 90
- Key_AE = 196
- Key_OE = 214
- Key_UE = 220
- Key_SharpS = 223
+ Key_None = 0
+ Key_Backspace = 8
+ Key_Tab = 9
+ Key_Return = 13
+ Key_Escape = 27
+ Key_Space = 32
+ Key_Asterisk = 42
+ Key_Plus = 43
+ Key_Comma = 44
+ Key_Minus = 45
+ Key_Point = 46
+ Key_Number0 = 48
+ Key_Number1 = 49
+ Key_Number2 = 50
+ Key_Number3 = 51
+ Key_Number4 = 52
+ Key_Number5 = 53
+ Key_Number6 = 54
+ Key_Number7 = 55
+ Key_Number8 = 56
+ Key_Number9 = 57
+ Key_A = 65
+ Key_B = 66
+ Key_C = 67
+ Key_D = 68
+ Key_E = 69
+ Key_F = 70
+ Key_G = 71
+ Key_H = 72
+ Key_I = 73
+ Key_J = 74
+ Key_K = 75
+ Key_L = 76
+ Key_M = 77
+ Key_N = 78
+ Key_O = 79
+ Key_P = 80
+ Key_Q = 81
+ Key_R = 82
+ Key_S = 83
+ Key_T = 84
+ Key_U = 85
+ Key_V = 86
+ Key_W = 87
+ Key_X = 88
+ Key_Y = 89
+ Key_Z = 90
+ Key_Circumflex = 94
+ Key_AE = 196
+ Key_OE = 214
+ Key_UE = 220
+ Key_SharpS = 223
# Not part of Unicode:
- Key_Insert = 1000
+ Key_Insert = 1000
Key_Delete
Key_Left
Key_Right
diff --git a/src/nigui/private/gtk3/gtk3.nim b/src/nigui/private/gtk3/gtk3.nim
index b1e218f..1edf03c 100755
--- a/src/nigui/private/gtk3/gtk3.nim
+++ b/src/nigui/private/gtk3/gtk3.nim
@@ -421,6 +421,9 @@ proc gtk_clipboard_store*(clipboard: pointer) {.importc: "gtk_clipboard_store",
proc gtk_accelerator_get_default_mod_mask*(): cint {.importc: "gtk_accelerator_get_default_mod_mask", libgtk3.}
+proc gtk_im_multicontext_new*(): pointer {.importc: "gtk_im_multicontext_new", libgtk3.}
+proc gtk_im_context_filter_keypress*(context: pointer, event: var GdkEventKey): bool {.importc: "gtk_im_context_filter_keypress", libgtk3.}
+
# ----------------------------------------------------------------------------------------
# Drawing Related Procs
diff --git a/src/nigui/private/gtk3/platform_impl.nim b/src/nigui/private/gtk3/platform_impl.nim
index 6bf791a..e0635c1 100755
--- a/src/nigui/private/gtk3/platform_impl.nim
+++ b/src/nigui/private/gtk3/platform_impl.nim
@@ -62,6 +62,7 @@ proc pWindowConfigureSignal(windowHandle, event, data: pointer): bool {.cdecl.}
proc pKeyvalToKey(keyval: cint): Key =
result = case keyval
+ of 65106: Key_Circumflex
of 65289: Key_Tab
of 65293: Key_Return
of 65307: Key_Escape
@@ -79,59 +80,68 @@ proc pKeyvalToKey(keyval: cint): Key =
else: cast[Key](keyval.unicodeToUpper)
proc pWindowKeyPressSignal(widget: pointer, event: var GdkEventKey, data: pointer): bool {.cdecl.} =
- # echo "window keyPressCallback"
-
- # echo event.keyval
- # echo event.hardware_keycode
-
- # echo $gdk_keyval_to_unicode(event.keyval)
- var unicode = gdk_keyval_to_unicode(event.keyval)
- # if unicode == 0:
- # unicode = event.keyval
-
let window = cast[WindowImpl](data)
+ window.fKeyPressed = pKeyvalToKey(event.keyval)
+ if gtk_im_context_filter_keypress(window.fIMContext, event) and window.fKeyPressed == Key_None:
+ return
var evt = new WindowKeyEvent
evt.window = window
- evt.key = pKeyvalToKey(event.keyval)
+ evt.key = window.fKeyPressed
if evt.key == Key_None:
echo "Unkown key value: ", event.keyval
return
-
evt.character = $event.`string`
- evt.unicode = unicode
-
+ evt.unicode = gdk_keyval_to_unicode(event.keyval)
try:
window.handleKeyDownEvent(evt)
- result = evt.cancel
except:
handleException()
+ result = evt.cancel
proc pControlKeyPressSignal(widget: pointer, event: var GdkEventKey, data: pointer): bool {.cdecl.} =
-
- # echo "control keyPressCallback"
-
- # echo $gdk_keyval_to_unicode(event.keyval)
- var unicode = gdk_keyval_to_unicode(event.keyval)
-
- # if unicode == 0:
- # unicode = event.keyval
-
let control = cast[ControlImpl](data)
+ control.fKeyPressed = pKeyvalToKey(event.keyval)
+ if gtk_im_context_filter_keypress(control.fIMContext, event) and control.fKeyPressed == Key_None:
+ return
var evt = new ControlKeyEvent
evt.control = control
- evt.key = pKeyvalToKey(event.keyval)
+ evt.key = control.fKeyPressed
if evt.key == Key_None:
echo "Unkown key value: ", event.keyval
return
evt.character = $event.`string`
- evt.unicode = unicode
-
+ evt.unicode = gdk_keyval_to_unicode(event.keyval)
try:
control.handleKeyDownEvent(evt)
except:
handleException()
+ result = evt.cancel
- return evt.cancel
+proc pWindowIMContextCommitSignal(context: pointer, str: cstring, data: pointer) {.cdecl.} =
+ let window = cast[WindowImpl](data)
+ var evt = new WindowKeyEvent
+ evt.window = window
+ evt.character = $str
+ evt.unicode = evt.character.runeAt(0).toUpper().int
+ evt.key = window.fKeyPressed
+ window.fKeyPressed = Key_None
+ try:
+ window.handleKeyDownEvent(evt)
+ except:
+ handleException()
+
+proc pControlIMContextCommitSignal(context: pointer, str: cstring, data: pointer) {.cdecl.} =
+ let control = cast[ControlImpl](data)
+ var evt = new ControlKeyEvent
+ evt.control = control
+ evt.character = $str
+ evt.unicode = evt.character.runeAt(0).toUpper().int
+ evt.key = control.fKeyPressed
+ control.fKeyPressed = Key_None
+ try:
+ control.handleKeyDownEvent(evt)
+ except:
+ handleException()
method focus(control: ControlImpl) =
gtk_widget_grab_focus(control.fHandle)
@@ -618,6 +628,9 @@ proc init(window: WindowImpl) =
gtk_scrolled_window_set_policy(window.fInnerHandle, GTK_POLICY_ALWAYS, GTK_POLICY_ALWAYS)
discard g_signal_connect_data(window.fInnerHandle, "draw", pMainScrollbarDraw, nil)
+ window.fIMContext = gtk_im_multicontext_new()
+ discard g_signal_connect_data(window.fIMContext, "commit", pWindowIMContextCommitSignal, cast[pointer](window))
+
method destroy(window: WindowImpl) =
procCall window.Window.destroy()
gtk_widget_destroy(window.fHandle)
@@ -758,6 +771,9 @@ proc init(control: ControlImpl) =
gtk_widget_add_events(control.fHandle, GDK_BUTTON_RELEASE_MASK)
discard g_signal_connect_data(control.fHandle, "button-release-event", pControlButtonReleaseSignal, cast[pointer](control))
+ control.fIMContext = gtk_im_multicontext_new()
+ discard g_signal_connect_data(control.fIMContext, "commit", pControlIMContextCommitSignal, cast[pointer](control))
+
procCall control.Control.init()
method destroy(control: ControlImpl) =
diff --git a/src/nigui/private/gtk3/platform_types1.nim b/src/nigui/private/gtk3/platform_types1.nim
index 505013b..5266e2f 100755
--- a/src/nigui/private/gtk3/platform_types1.nim
+++ b/src/nigui/private/gtk3/platform_types1.nim
@@ -6,6 +6,8 @@ type
WindowImpl* = ref object of Window
fHandle: pointer
fInnerHandle: pointer
+ fIMContext: pointer
+ fKeyPressed: Key
ControlImpl* = ref object of Control
fHandle: pointer
@@ -14,6 +16,8 @@ type
fHAdjust: pointer
fVAdjust: pointer
fDeadCornerHandle: pointer
+ fIMContext: pointer
+ fKeyPressed: Key
CanvasImpl* = ref object of Canvas
fSurface: pointer
diff --git a/src/nigui/private/windows/platform_impl.nim b/src/nigui/private/windows/platform_impl.nim
index 78dace3..8e072ff 100755
--- a/src/nigui/private/windows/platform_impl.nim
+++ b/src/nigui/private/windows/platform_impl.nim
@@ -20,6 +20,7 @@ const pCustomControlWindowClass = "3"
var pDefaultParentWindow: pointer
var pKeyState: KeyState
+var pKeyDownKey: Key
# needed to calculate clicks:
var pLastMouseButtonDownControl: Control
@@ -221,10 +222,10 @@ proc pVirtualKeyToKey(keyval: int): Key =
of 46: Key_Delete
else: cast[Key](keyval.unicodeToUpper)
-proc pHandleWMKEYDOWNOrWMCHAR(window: Window, control: Control, unicode: int, key: Key): bool =
+proc pHandleWMKEYDOWNOrWMCHAR(window: Window, control: Control, unicode: int): bool =
var windowEvent = new WindowKeyEvent
windowEvent.window = window
- windowEvent.key = key
+ windowEvent.key = pKeyDownKey
if windowEvent.key == Key_None:
echo "WM_CHAR: Unkown key value: ", unicode
return
@@ -252,19 +253,22 @@ proc pHandleWMKEYDOWNOrWMCHAR(window: Window, control: Control, unicode: int, ke
proc pHandleWMKEYDOWN(window: Window, control: Control, wParam, lParam: pointer): bool =
if not GetKeyboardState(pKeyState): pRaiseLastOSError()
+ pKeyDownKey = pVirtualKeyToKey(cast[int](wParam))
+ # Save the key for WM_CHAR, because WM_CHAR only gets the key combined with the dead key state
var widestring = newString(2)
let scancode = int32((cast[int](lParam) shr 8) and 0xFFFFFF00)
if scancode == 10496:
# When the dead key "^" on German keyboard is pressed, don't call ToUnicode(), because this would destroy the dead key state
- return
+ pKeyDownKey = Key_Circumflex
+ return pHandleWMKEYDOWNOrWMCHAR(window, control, 0)
let ret = ToUnicode(cast[int](wParam).int32, scancode, pKeyState, widestring, 1, 0)
if ret == 1:
return # Unicode characters are handled by WM_CHAR
- result = pHandleWMKEYDOWNOrWMCHAR(window, control, 0, pVirtualKeyToKey(cast[int](wParam)))
+ result = pHandleWMKEYDOWNOrWMCHAR(window, control, 0)
proc pHandleWMCHAR(window: Window, control: Control, wParam, lParam: pointer): bool =
let unicode = cast[int](wParam)
- result = pHandleWMKEYDOWNOrWMCHAR(window, control, unicode, cast[Key](unicode.unicodeToUpper))
+ result = pHandleWMKEYDOWNOrWMCHAR(window, control, unicode)
proc pWindowWndProc(hWnd: pointer, uMsg: int32, wParam, lParam: pointer): pointer {.cdecl.} =
case uMsg