Changed AreaHandler.Key() to return a boolean value indicating if the event was handled; implemented this on Windows. It does sledgehammer some edge cases I wanted to avoid, but it also avoids fussing about scrolling and focus and what not.
This commit is contained in:
parent
f3ca234dda
commit
e5c74b832b
|
@ -74,10 +74,10 @@ type AreaHandler interface {
|
||||||
Mouse(e MouseEvent)
|
Mouse(e MouseEvent)
|
||||||
|
|
||||||
// Key is called when the Area receives a keyboard event.
|
// Key is called when the Area receives a keyboard event.
|
||||||
// You are allowed to do nothing in this handler (to ignore keyboard events).
|
// Return true to indicate that you handled the event; return false to indicate that you did not and let the system handle the event.
|
||||||
|
// You are allowed to do nothing in this handler (to ignore keyboard events); in this case, return false.
|
||||||
// See KeyEvent for details.
|
// See KeyEvent for details.
|
||||||
// After handling the key event, package ui will decide whether to perform platform-dependent event chain continuation based on that platform's designated action (so it is not possible to override global key events, such as Alt-Tab, this way).
|
Key(e KeyEvent) (handled bool)
|
||||||
Key(e KeyEvent)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// MouseEvent contains all the information for a mous event sent by Area.Mouse.
|
// MouseEvent contains all the information for a mous event sent by Area.Mouse.
|
||||||
|
@ -140,7 +140,7 @@ func (e MouseEvent) HeldBits() (h uintptr) {
|
||||||
// on US English QWERTY keyboards; see Key for details.
|
// on US English QWERTY keyboards; see Key for details.
|
||||||
//
|
//
|
||||||
// If a key is pressed that is not supported by Key, ExtKey,
|
// If a key is pressed that is not supported by Key, ExtKey,
|
||||||
// or Modifiers, no KeyEvent will be produced.
|
// or Modifiers, no KeyEvent will be produced and package ui will behave as if false was returned from the event handler.
|
||||||
type KeyEvent struct {
|
type KeyEvent struct {
|
||||||
// Key is a byte representing a character pressed
|
// Key is a byte representing a character pressed
|
||||||
// in the typewriter section of the keyboard.
|
// in the typewriter section of the keyboard.
|
||||||
|
|
|
@ -380,19 +380,10 @@ static LRESULT CALLBACK areaWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM
|
||||||
heldButtons = (uintptr_t) GET_KEYSTATE_WPARAM(wParam);
|
heldButtons = (uintptr_t) GET_KEYSTATE_WPARAM(wParam);
|
||||||
areaMouseEvent(hwnd, data, which, TRUE, heldButtons, lParam);
|
areaMouseEvent(hwnd, data, which, TRUE, heldButtons, lParam);
|
||||||
return TRUE;
|
return TRUE;
|
||||||
case WM_KEYDOWN:
|
case msgAreaKeyDown:
|
||||||
areaKeyEvent(data, FALSE, wParam, lParam);
|
return (LRESULT) areaKeyEvent(data, FALSE, wParam, lParam);
|
||||||
return 0;
|
case msgAreaKeyUp:
|
||||||
case WM_KEYUP:
|
return (LRESULT) areaKeyEvent(data, TRUE, wParam, lParam);
|
||||||
areaKeyEvent(data, TRUE, wParam, lParam);
|
|
||||||
return 0;
|
|
||||||
// Alt+[anything] and F10 send these instead and require us to return to DefWindowProc() so global keystrokes such as Alt+Tab can be processed
|
|
||||||
case WM_SYSKEYDOWN:
|
|
||||||
areaKeyEvent(data, FALSE, wParam, lParam);
|
|
||||||
return DefWindowProcW(hwnd, uMsg, wParam, lParam);
|
|
||||||
case WM_SYSKEYUP:
|
|
||||||
areaKeyEvent(data, TRUE, wParam, lParam);
|
|
||||||
return DefWindowProcW(hwnd, uMsg, wParam, lParam);
|
|
||||||
case msgAreaSizeChanged:
|
case msgAreaSizeChanged:
|
||||||
adjustAreaScrollbars(hwnd, data);
|
adjustAreaScrollbars(hwnd, data);
|
||||||
repaintArea(hwnd); // this calls for an update
|
repaintArea(hwnd); // this calls for an update
|
||||||
|
|
|
@ -152,7 +152,7 @@ func finishAreaMouseEvent(data unsafe.Pointer, cbutton C.DWORD, up C.BOOL, heldB
|
||||||
}
|
}
|
||||||
|
|
||||||
//export areaKeyEvent
|
//export areaKeyEvent
|
||||||
func areaKeyEvent(data unsafe.Pointer, up C.BOOL, wParam C.WPARAM, lParam C.LPARAM) {
|
func areaKeyEvent(data unsafe.Pointer, up C.BOOL, wParam C.WPARAM, lParam C.LPARAM) C.BOOL {
|
||||||
var ke KeyEvent
|
var ke KeyEvent
|
||||||
|
|
||||||
a := (*area)(data)
|
a := (*area)(data)
|
||||||
|
@ -180,10 +180,14 @@ func areaKeyEvent(data unsafe.Pointer, up C.BOOL, wParam C.WPARAM, lParam C.LPAR
|
||||||
ke.ExtKey = xke.ExtKey
|
ke.ExtKey = xke.ExtKey
|
||||||
} else if ke.Modifiers == 0 {
|
} else if ke.Modifiers == 0 {
|
||||||
// no key, extkey, or modifiers; do nothing
|
// no key, extkey, or modifiers; do nothing
|
||||||
return
|
return C.FALSE
|
||||||
}
|
}
|
||||||
ke.Up = up != C.FALSE
|
ke.Up = up != C.FALSE
|
||||||
a.handler.Key(ke)
|
handled := a.handler.Key(ke)
|
||||||
|
if handled {
|
||||||
|
return C.TRUE
|
||||||
|
}
|
||||||
|
return C.FALSE
|
||||||
}
|
}
|
||||||
|
|
||||||
// all mappings come from GLFW - https://github.com/glfw/glfw/blob/master/src/win32_window.c#L152
|
// all mappings come from GLFW - https://github.com/glfw/glfw/blob/master/src/win32_window.c#L152
|
||||||
|
|
|
@ -8,9 +8,31 @@
|
||||||
// this also assumes WC_TABCONTROL is longer than areaWindowClass
|
// this also assumes WC_TABCONTROL is longer than areaWindowClass
|
||||||
#define NCLASSNAME (sizeof WC_TABCONTROL / sizeof WC_TABCONTROL[0])
|
#define NCLASSNAME (sizeof WC_TABCONTROL / sizeof WC_TABCONTROL[0])
|
||||||
|
|
||||||
void uimsgloop_area(MSG *msg)
|
void uimsgloop_area(HWND active, HWND focus, MSG *msg)
|
||||||
{
|
{
|
||||||
|
MSG copy;
|
||||||
|
|
||||||
|
copy = *msg;
|
||||||
|
switch (copy.message) {
|
||||||
|
case WM_KEYDOWN:
|
||||||
|
case WM_SYSKEYDOWN: // Alt+[anything] and F10 send these instead
|
||||||
|
copy.message = msgAreaKeyDown;
|
||||||
|
break;
|
||||||
|
case WM_KEYUP:
|
||||||
|
case WM_SYSKEYUP:
|
||||||
|
copy.message = msgAreaKeyUp;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
goto notkey;
|
||||||
|
}
|
||||||
|
// if we handled the key, don't do the default behavior
|
||||||
// don't call TranslateMessage(); we do our own keyboard handling
|
// don't call TranslateMessage(); we do our own keyboard handling
|
||||||
|
if (DispatchMessage(©) != FALSE)
|
||||||
|
return;
|
||||||
|
// TODO move this under notkey?
|
||||||
|
if (IsDialogMessage(active, msg) != 0)
|
||||||
|
return;
|
||||||
|
notkey:
|
||||||
DispatchMessage(msg);
|
DispatchMessage(msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -70,7 +92,7 @@ void uimsgloop(void)
|
||||||
if (GetClassNameW(focus, classchk, NCLASSNAME) == 0)
|
if (GetClassNameW(focus, classchk, NCLASSNAME) == 0)
|
||||||
xpanic("error getting name of focused window class for Area check", GetLastError());
|
xpanic("error getting name of focused window class for Area check", GetLastError());
|
||||||
if (wcscmp(classchk, areaWindowClass) == 0) {
|
if (wcscmp(classchk, areaWindowClass) == 0) {
|
||||||
uimsgloop_area(&msg);
|
uimsgloop_area(active, focus, &msg);
|
||||||
continue;
|
continue;
|
||||||
} else if (wcscmp(classchk, WC_TABCONTROL) == 0) {
|
} else if (wcscmp(classchk, WC_TABCONTROL) == 0) {
|
||||||
uimsgloop_tab(active, focus, &msg);
|
uimsgloop_tab(active, focus, &msg);
|
||||||
|
|
|
@ -34,6 +34,8 @@ enum {
|
||||||
msgTabCurrentTabHasChildren,
|
msgTabCurrentTabHasChildren,
|
||||||
msgBeginModal,
|
msgBeginModal,
|
||||||
msgEndModal,
|
msgEndModal,
|
||||||
|
msgAreaKeyDown,
|
||||||
|
msgAreaKeyUp,
|
||||||
};
|
};
|
||||||
|
|
||||||
// uitask_windows.c
|
// uitask_windows.c
|
||||||
|
|
|
@ -63,14 +63,16 @@ type testwin struct {
|
||||||
wsmall Window
|
wsmall Window
|
||||||
}
|
}
|
||||||
|
|
||||||
type areaHandler struct{}
|
type areaHandler struct {
|
||||||
|
handled bool
|
||||||
|
}
|
||||||
func (a *areaHandler) Paint(r image.Rectangle) *image.RGBA {
|
func (a *areaHandler) Paint(r image.Rectangle) *image.RGBA {
|
||||||
i := image.NewRGBA(r)
|
i := image.NewRGBA(r)
|
||||||
draw.Draw(i, r, &image.Uniform{color.RGBA{128,0,128,255}}, image.ZP, draw.Src)
|
draw.Draw(i, r, &image.Uniform{color.RGBA{128,0,128,255}}, image.ZP, draw.Src)
|
||||||
return i
|
return i
|
||||||
}
|
}
|
||||||
func (a *areaHandler) Mouse(me MouseEvent) { fmt.Printf("%#v\n", me) }
|
func (a *areaHandler) Mouse(me MouseEvent) { fmt.Printf("%#v\n", me) }
|
||||||
func (a *areaHandler) Key(ke KeyEvent) { fmt.Printf("%#v %q\n", ke, ke.Key) }
|
func (a *areaHandler) Key(ke KeyEvent) bool { fmt.Printf("%#v %q\n", ke, ke.Key); return a.handled }
|
||||||
|
|
||||||
func (tw *testwin) addfe() {
|
func (tw *testwin) addfe() {
|
||||||
tw.festart = NewButton("Start")
|
tw.festart = NewButton("Start")
|
||||||
|
@ -169,7 +171,7 @@ func (tw *testwin) make(done chan struct{}) {
|
||||||
tw.nt.Append("Tab 2", Space())
|
tw.nt.Append("Tab 2", Space())
|
||||||
tw.t.Append("Tab", tw.nt)
|
tw.t.Append("Tab", tw.nt)
|
||||||
tw.t.Append("Space", Space())
|
tw.t.Append("Space", Space())
|
||||||
tw.a = NewArea(200, 200, &areaHandler{})
|
tw.a = NewArea(200, 200, &areaHandler{false})
|
||||||
tw.t.Append("Area", tw.a)
|
tw.t.Append("Area", tw.a)
|
||||||
tw.spw = NewHorizontalStack(
|
tw.spw = NewHorizontalStack(
|
||||||
NewButton("hello"),
|
NewButton("hello"),
|
||||||
|
@ -233,7 +235,7 @@ func (tw *testwin) make(done chan struct{}) {
|
||||||
NewVerticalStack(
|
NewVerticalStack(
|
||||||
NewButton("Small"),
|
NewButton("Small"),
|
||||||
NewButton("Small 2"),
|
NewButton("Small 2"),
|
||||||
NewArea(200, 200, &areaHandler{})))
|
NewArea(200, 200, &areaHandler{true})))
|
||||||
tw.wsmall.Show()
|
tw.wsmall.Show()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue