[PATCH wfits v2] core: Add a wrapper for the keyboard

Eoff, Ullysses A ullysses.a.eoff at intel.com
Thu Sep 26 12:13:39 PDT 2013


> -----Original Message-----
> From: wayland-devel-bounces+ullysses.a.eoff=intel.com at lists.freedesktop.org [mailto:wayland-devel-
> bounces+ullysses.a.eoff=intel.com at lists.freedesktop.org] On Behalf Of Neil Roberts
> Sent: Wednesday, September 25, 2013 4:33 PM
> To: wayland-devel at lists.freedesktop.org
> Subject: [PATCH wfits v2] core: Add a wrapper for the keyboard
> 
> Ok, here's a second version of the patch with all of the suggested changes.
> 
> > So we must only want one xkb context per display. Ok.
> 
> Yes, I think we only really want one global xkb context but the
> display seemed like a convenient place to attach it and ensure that it
> will be destructed.
> 
> > We should explicitly initialize keys_ here with some default:
> 
> Ok
> 
> > I prefer to always use brackets in all control structures even
> > if there is only one statement.
> 
> Ok. I also changed places where I was using brace hugging because I
> had just assumed you were using the Wayland/Linux style.
> 

I don't mind brace hugging.  I'm not fully familiar with the
Wayland/Linux style yet; is there a document for it?  Either way, it's
probably best if I add a coding style document to this project.  I
use the style that I've always been taught... but of course I can't
expect everyone to know what that is ;).  I'll try not to be too
critical or picky about style until I get it documented.

> > But, instead of iterating here why not use std::find(...):
> 
> Ok, I changed it to use std::find().
> 

That seems nicer ;)

> > How about:
> > 	if (not keyPressed(key))
> > 	{
> > 		keys_.push_back(key);
> > 	}
> 
> Sure.
> 
> > This is an odd way to remove the key from the vector, and was a bit
> > hard to understand initially, but I suppose it's faster than
> > keys_.erase(...).
> 
> Yeah, I copied this trick from Weston because I thought it was quite
> neat. But in this case I guess there's absolutely no point in
> optimising it so let's just use vector::erase() to make it more
> readable.
> 

Cool, yeh optimization is not critical here.

> > Probably prefer const function here:
> > 	bool hasFocus(wl_surface*) const;
> 
> Ok. You might want to fix the one in pointer.cpp too in that case.
> 

Fair enough, I'll fix that.  I'm sure there's likely other places where
const corrections need to be done too.

> > I'd prefer to see all class scoped typedefs at the top of the class
> > declaration, just before the "public" keyword (which effectively
> > keeps them private by default). Also, for simplicity, we should
> > typedef the vector, too:
> 
> Ok. I've added a typedef for the vector and moved it to the top. I've
> removed the iterator types because once you have the typedef for the
> vector then typing Keys::iterator doesn't seem such a pain.
> 

Yeh that's not so bad.

> Regards,
> - Neil
>

Thanks Neil!  I'll get these patches merged.


 
> ------- >8 --------------- (use git am --scissors to automatically chop here)
> 
> This adds a wrapper for a wl_keyboard in a similar way to the pointer
> wrapper. It keeps track of the keys that are pressed so that they can
> be quickly verified. wayland-fits now depends on libxkbcommon so that
> the keyboard wrapper can pass the keymap to it and get the modifier
> indices.
> ---
>  configure.ac               |   2 +
>  src/test/Makefile.am       |   2 +
>  src/test/core/Makefile.am  |   3 +
>  src/test/core/display.cpp  |  16 ++++
>  src/test/core/display.h    |   3 +
>  src/test/core/keyboard.cpp | 216 +++++++++++++++++++++++++++++++++++++++++++++
>  src/test/core/keyboard.h   | 106 ++++++++++++++++++++++
>  src/test/efl/Makefile.am   |   2 +
>  src/test/gtk+/Makefile.am  |   2 +
>  9 files changed, 352 insertions(+)
>  create mode 100644 src/test/core/keyboard.cpp
>  create mode 100644 src/test/core/keyboard.h
> 
> diff --git a/configure.ac b/configure.ac
> index de84adf..5ad59ca 100644
> --- a/configure.ac
> +++ b/configure.ac
> @@ -61,6 +61,8 @@ PKG_CHECK_MODULES([WAYLAND],
>  )
>  PKG_CHECK_MODULES(WAYLAND_SERVER, [wayland-server >= wayland_req_version])
> 
> +PKG_CHECK_MODULES([XKBCOMMON], xkbcommon)
> +
>  have_weston="no"
>  want_weston_extensions="auto"
>  AC_ARG_ENABLE([weston-extensions],
> diff --git a/src/test/Makefile.am b/src/test/Makefile.am
> index ba5e5ce..e50c0fc 100644
> --- a/src/test/Makefile.am
> +++ b/src/test/Makefile.am
> @@ -14,6 +14,7 @@ wfits_SOURCES =				\
>  wfits_LDADD =				\
>  	core/libwfits-core.la		\
>  	$(CHECK_LIBS)			\
> +	$(XKBCOMMON_LIBS)		\
>  	$(WAYLAND_LIBS)			\
>  	$(BOOST_LIBS)
> 
> @@ -23,6 +24,7 @@ wfits_LDFLAGS =				\
>  wfits_CPPFLAGS =			\
>  	-I$(top_srcdir)/src		\
>  	$(CHECK_CFLAGS)			\
> +	$(XKBCOMMON_CFLAGS)		\
>  	$(WAYLAND_CFLAGS)		\
>  	$(BOOST_CPPFLAGS)
> 
> diff --git a/src/test/core/Makefile.am b/src/test/core/Makefile.am
> index bff1c5a..3a93a67 100644
> --- a/src/test/core/Makefile.am
> +++ b/src/test/core/Makefile.am
> @@ -3,6 +3,7 @@ noinst_LTLIBRARIES = libwfits-core.la
>  libwfits_core_la_SOURCES =		\
>  	display.cpp			\
>  	compositor.cpp			\
> +	keyboard.cpp			\
>  	shell.cpp			\
>  	seat.cpp			\
>  	pointer.cpp			\
> @@ -23,11 +24,13 @@ libwfits_core_la_SOURCES =		\
> 
>  libwfits_core_la_LIBADD =		\
>  	$(WAYLAND_LIBS)			\
> +	$(XKBCOMMON_LIBS)		\
>  	$(CHECK_LIBS)
> 
>  libwfits_core_la_CPPFLAGS =		\
>  	-I$(top_srcdir)/src		\
>  	$(WAYLAND_CFLAGS)		\
> +	$(XKBCOMMON_CFLAGS)		\
>  	$(CHECK_CFLAGS)
> 
>  AM_CXXFLAGS =				\
> diff --git a/src/test/core/display.cpp b/src/test/core/display.cpp
> index 1c29dbf..55cb673 100644
> --- a/src/test/core/display.cpp
> +++ b/src/test/core/display.cpp
> @@ -30,6 +30,7 @@ Display::Display()
>  	: wl_display_(wl_display_connect(0))
>  	, wl_registry_(NULL)
>  	, globals_()
> +	, xkbContext_(NULL)
>  {
>  	ASSERT(wl_display_ != NULL);
> 
> @@ -49,6 +50,10 @@ Display::Display()
> 
>  /*virtual*/ Display::~Display()
>  {
> +	if (xkbContext_)
> +	{
> +		xkb_context_unref(xkbContext_);
> +	}
>  	wl_registry_destroy(wl_registry_);
>  	wl_display_disconnect(*this);
>  }
> @@ -69,6 +74,17 @@ void Display::yield(const unsigned time) const
>  	usleep(time);
>  }
> 
> +struct xkb_context *Display::xkbContext() const
> +{
> +	if (xkbContext_ == NULL)
> +	{
> +		xkbContext_ = xkb_context_new((enum xkb_context_flags) 0);
> +		ASSERT(xkbContext_ != NULL);
> +	}
> +
> +	return xkbContext_;
> +}
> +
>  /*static*/ void Display::global(
>  	void *data, struct wl_registry *wl_registry, uint32_t id,
>  	const char* interface, uint32_t version)
> diff --git a/src/test/core/display.h b/src/test/core/display.h
> index 0a4c10a..bf09057 100644
> --- a/src/test/core/display.h
> +++ b/src/test/core/display.h
> @@ -25,6 +25,7 @@
> 
>  #include <map>
>  #include <wayland-client.h>
> +#include <xkbcommon/xkbcommon.h>
>  #include "test/tools.h"
> 
>  namespace wfits {
> @@ -63,6 +64,7 @@ public:
>  	void roundtrip() const;
>  	void dispatch() const;
>  	void yield(const unsigned = 0.001 * 1e6) const;
> +	struct xkb_context *xkbContext() const;
> 
>  	operator wl_display*() const { return wl_display_; }
>  	operator wl_registry*() const { return wl_registry_; }
> @@ -74,6 +76,7 @@ private:
>  	wl_display	*wl_display_;
>  	wl_registry	*wl_registry_;
>  	Globals		globals_;
> +	mutable struct xkb_context *xkbContext_;
>  };
> 
>  } // namespace core
> diff --git a/src/test/core/keyboard.cpp b/src/test/core/keyboard.cpp
> new file mode 100644
> index 0000000..2c766c6
> --- /dev/null
> +++ b/src/test/core/keyboard.cpp
> @@ -0,0 +1,216 @@
> +/*
> + * Copyright © 2013 Intel Corporation
> + *
> + * Permission to use, copy, modify, distribute, and sell this software and
> + * its documentation for any purpose is hereby granted without fee, provided
> + * that the above copyright notice appear in all copies and that both that
> + * copyright notice and this permission notice appear in supporting
> + * documentation, and that the name of the copyright holders not be used in
> + * advertising or publicity pertaining to distribution of the software
> + * without specific, written prior permission.  The copyright holders make
> + * no representations about the suitability of this software for any
> + * purpose.  It is provided "as is" without express or implied warranty.
> + *
> + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
> + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
> + * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
> + * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
> + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
> + * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
> + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
> + */
> +
> +#include <sys/mman.h>
> +
> +#include "keyboard.h"
> +
> +namespace wfits {
> +namespace test {
> +namespace core {
> +
> +Keyboard::Keyboard(const Seat& seat)
> +	: seat_(seat)
> +	, focus_(NULL)
> +	, focusSerial_(0)
> +	, wl_keyboard_(NULL)
> +	, keys_()
> +	, modsDepressed_(0)
> +	, modsLatched_(0)
> +	, modsLocked_(0)
> +	, group_(0)
> +	, keymap_(NULL)
> +{
> +	ASSERT(seat.capabilities() & WL_SEAT_CAPABILITY_KEYBOARD);
> +
> +	wl_keyboard_ = wl_seat_get_keyboard(seat);
> +
> +	ASSERT(wl_keyboard_ != NULL);
> +
> +	wl_keyboard_set_user_data(*this, this);
> +
> +	static const wl_keyboard_listener listener = {
> +		keymap, enter, leave, key, modifiers
> +	};
> +
> +	wl_keyboard_add_listener(*this, &listener, this);
> +}
> +
> +/*virtual*/ Keyboard::~Keyboard()
> +{
> +	if (keymap_)
> +	{
> +		xkb_map_unref(keymap_);
> +	}
> +
> +	wl_keyboard_destroy(*this);
> +}
> +
> +bool Keyboard::hasFocus(wl_surface* surface) const
> +{
> +	return focus() == surface;
> +}
> +
> +bool Keyboard::keyPressed(uint32_t key) const
> +{
> +	return std::find(keys_.begin(), keys_.end(), key) != keys_.end();
> +}
> +
> +void Keyboard::pressKey(uint32_t key)
> +{
> +	if (not keyPressed(key))
> +	{
> +		keys_.push_back(key);
> +	}
> +}
> +
> +void Keyboard::releaseKey(uint32_t key)
> +{
> +	Keys::iterator it = std::find(keys_.begin(), keys_.end(), key);
> +
> +	if (it != keys_.end())
> +	{
> +		keys_.erase(it);
> +	}
> +}
> +
> +/* static */ void Keyboard::keymap(void *data,
> +				   struct wl_keyboard *wl_keyboard,
> +				   uint32_t format,
> +				   int32_t fd,
> +				   uint32_t size)
> +{
> +	Keyboard* keyboard = static_cast<Keyboard*>(data);
> +	struct xkb_keymap *keymap;
> +	char *map_str;
> +
> +	ASSERT(wl_keyboard == *keyboard);
> +	ASSERT(format == WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1);
> +
> +	map_str = (char *) mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0);
> +	ASSERT(map_str != MAP_FAILED);
> +
> +	keymap = xkb_map_new_from_string(keyboard->seat_.display().xkbContext(),
> +					 map_str,
> +					 XKB_KEYMAP_FORMAT_TEXT_V1,
> +					 (enum xkb_keymap_compile_flags) 0);
> +	munmap(map_str, size);
> +	close(fd);
> +
> +	ASSERT(keymap != NULL);
> +
> +	if (keyboard->keymap_ != NULL)
> +	{
> +		xkb_map_unref(keyboard->keymap_);
> +	}
> +
> +	keyboard->keymap_ = keymap;
> +}
> +
> +/* static */ void Keyboard::enter(void *data,
> +				  struct wl_keyboard *wl_keyboard,
> +				  uint32_t serial,
> +				  struct wl_surface *surface,
> +				  struct wl_array *keys)
> +{
> +	Keyboard* keyboard = static_cast<Keyboard*>(data);
> +	ASSERT(wl_keyboard == *keyboard);
> +
> +	keyboard->focus_ = surface;
> +	keyboard->focusSerial_ = serial;
> +
> +	keyboard->keys_.resize(keys->size / sizeof(uint32_t));
> +	memcpy(&keyboard->keys_[0], keys->data, keys->size);
> +}
> +
> +/* static */ void Keyboard::leave(void *data,
> +				  struct wl_keyboard *wl_keyboard,
> +				  uint32_t serial,
> +				  struct wl_surface *surface)
> +{
> +	Keyboard* keyboard = static_cast<Keyboard*>(data);
> +	ASSERT(wl_keyboard == *keyboard);
> +
> +	keyboard->focus_ = NULL;
> +	keyboard->keys_.resize(0);
> +
> +	/* We don't want to reset the modifiers here because the
> +	 * compositor may still send updated modifier state if the
> +	 * surface has pointer focus */
> +}
> +
> +/* static */ void Keyboard::key(void *data,
> +				struct wl_keyboard *wl_keyboard,
> +				uint32_t serial,
> +				uint32_t time,
> +				uint32_t key,
> +				uint32_t state)
> +{
> +	Keyboard* keyboard = static_cast<Keyboard*>(data);
> +	ASSERT(wl_keyboard == *keyboard);
> +
> +	if (state == 0)
> +	{
> +		keyboard->releaseKey(key);
> +	}
> +	else
> +	{
> +		keyboard->pressKey(key);
> +	}
> +}
> +
> +/* static */ void Keyboard::modifiers(void *data,
> +				      struct wl_keyboard *wl_keyboard,
> +				      uint32_t serial,
> +				      uint32_t modsDepressed,
> +				      uint32_t modsLatched,
> +				      uint32_t modsLocked,
> +				      uint32_t group)
> +{
> +	Keyboard* keyboard = static_cast<Keyboard*>(data);
> +	ASSERT(wl_keyboard == *keyboard);
> +
> +	keyboard->modsDepressed_ = modsDepressed;
> +	keyboard->modsLatched_ = modsLatched;
> +	keyboard->modsLocked_ = modsLocked;
> +	keyboard->group_ = group;
> +}
> +
> +namespace wrapper {
> +
> +	TEST(Keyboard)
> +	{
> +		Display display;
> +		Seat seat(display);
> +		Keyboard keyboard(seat);
> +
> +		FAIL_UNLESS_EQUAL(&keyboard.seat(), &seat);
> +		FAIL_IF((wl_keyboard*)keyboard == NULL);
> +		FAIL_UNLESS_EQUAL(wl_keyboard_get_user_data(keyboard), &keyboard);
> +		FAIL_UNLESS(keyboard.hasFocus(NULL));
> +	}
> +
> +} // namespace wrapper
> +
> +} // namespace core
> +} // namespace test
> +} // namespace wfits
> diff --git a/src/test/core/keyboard.h b/src/test/core/keyboard.h
> new file mode 100644
> index 0000000..53398a2
> --- /dev/null
> +++ b/src/test/core/keyboard.h
> @@ -0,0 +1,106 @@
> +/*
> + * Copyright © 2013 Intel Corporation
> + *
> + * Permission to use, copy, modify, distribute, and sell this software and
> + * its documentation for any purpose is hereby granted without fee, provided
> + * that the above copyright notice appear in all copies and that both that
> + * copyright notice and this permission notice appear in supporting
> + * documentation, and that the name of the copyright holders not be used in
> + * advertising or publicity pertaining to distribution of the software
> + * without specific, written prior permission.  The copyright holders make
> + * no representations about the suitability of this software for any
> + * purpose.  It is provided "as is" without express or implied warranty.
> + *
> + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
> + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
> + * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
> + * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
> + * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
> + * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
> + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
> + */
> +
> +#ifndef __WFITS_CORE_KEYBOARD_H__
> +#define __WFITS_CORE_KEYBOARD_H__
> +
> +#include <xkbcommon/xkbcommon.h>
> +#include <vector>
> +#include "seat.h"
> +
> +namespace wfits {
> +namespace test {
> +namespace core {
> +
> +class Keyboard
> +{
> +	typedef std::vector<uint32_t> Keys;
> +
> +public:
> +	Keyboard(const Seat&);
> +
> +	virtual ~Keyboard();
> +
> +	operator wl_keyboard*() const { return wl_keyboard_; }
> +	const Seat& seat() const { return seat_; }
> +	wl_surface* focus() const { return focus_; }
> +	xkb_keymap* keymap() const { return keymap_; }
> +	const uint32_t focusSerial() const { return focusSerial_; }
> +
> +	bool hasFocus(wl_surface*) const;
> +
> +	const uint32_t modsDepressed() const { return modsDepressed_; }
> +	const uint32_t modsLatched() const { return modsLatched_; }
> +	const uint32_t modsLocked() const { return modsLocked_; }
> +	const uint32_t group() const { return group_; }
> +	bool keyPressed(uint32_t key) const;
> +
> +private:
> +	static void keymap(void *data,
> +			   struct wl_keyboard *wl_keyboard,
> +			   uint32_t format,
> +			   int32_t fd,
> +			   uint32_t size);
> +	static void enter(void *data,
> +			  struct wl_keyboard *wl_keyboard,
> +			  uint32_t serial,
> +			  struct wl_surface *surface,
> +			  struct wl_array *keys);
> +	static void leave(void *data,
> +			  struct wl_keyboard *wl_keyboard,
> +			  uint32_t serial,
> +			  struct wl_surface *surface);
> +	static void key(void *data,
> +			struct wl_keyboard *wl_keyboard,
> +			uint32_t serial,
> +			uint32_t time,
> +			uint32_t key,
> +			uint32_t state);
> +	static void modifiers(void *data,
> +			      struct wl_keyboard *wl_keyboard,
> +			      uint32_t serial,
> +			      uint32_t modsDepressed,
> +			      uint32_t modsLatched,
> +			      uint32_t modsLocked,
> +			      uint32_t group);
> +
> +	void pressKey(uint32_t key);
> +	void releaseKey(uint32_t key);
> +
> +	const Seat&	seat_;
> +	wl_surface*	focus_;
> +	uint32_t	focusSerial_;
> +	wl_keyboard*	wl_keyboard_;
> +
> +	std::vector<uint32_t> keys_;
> +	uint32_t modsDepressed_;
> +	uint32_t modsLatched_;
> +	uint32_t modsLocked_;
> +	uint32_t group_;
> +	struct xkb_keymap *keymap_;
> +};
> +
> +} // namespace core
> +} // namespace test
> +} // namespace wfits
> +
> +#endif
> diff --git a/src/test/efl/Makefile.am b/src/test/efl/Makefile.am
> index 104213d..85084be 100644
> --- a/src/test/efl/Makefile.am
> +++ b/src/test/efl/Makefile.am
> @@ -46,6 +46,7 @@ libwfits_efl_la_SOURCES = \
>  	test_window_fullscreen.cpp
> 
>  libwfits_efl_la_LIBADD =		\
> +	$(XKBCOMMON_LIBS)		\
>  	$(WAYLAND_LIBS)			\
>  	$(EFL_LIBS)			\
>  	$(CHECK_LIBS)
> @@ -53,6 +54,7 @@ libwfits_efl_la_LIBADD =		\
>  libwfits_efl_la_CPPFLAGS =		\
>  	-I$(top_srcdir)/src		\
>  	-DMEDIA_PATH=$(MEDIA)		\
> +	$(XKBCOMMON_CFLAGS)		\
>  	$(WAYLAND_CFLAGS)		\
>  	$(EFL_CFLAGS)			\
>  	$(CHECK_CFLAGS)
> diff --git a/src/test/gtk+/Makefile.am b/src/test/gtk+/Makefile.am
> index b19aa9c..aa12963 100644
> --- a/src/test/gtk+/Makefile.am
> +++ b/src/test/gtk+/Makefile.am
> @@ -10,12 +10,14 @@ libwfits_gtk_la_SOURCES =		\
> 
>  libwfits_gtk_la_LIBADD =		\
>  	$(WAYLAND_LIBS)			\
> +	$(XKBCOMMON_LIBS)		\
>  	$(GTK_LIBS)			\
>  	$(CHECK_LIBS)
> 
>  libwfits_gtk_la_CPPFLAGS =		\
>  	-I$(top_srcdir)/src		\
>  	$(WAYLAND_CFLAGS)		\
> +	$(XKBCOMMON_CFLAGS)		\
>  	$(GTK_CFLAGS)			\
>  	$(CHECK_CFLAGS)
> 
> --
> 1.8.3.1
> 
> _______________________________________________
> wayland-devel mailing list
> wayland-devel at lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/wayland-devel


More information about the wayland-devel mailing list