ManyKeyboard – Using Java HID API to handle Multiple Keyboard Input

I want to announce a small Java library I made for handling multiple keyboard input on a single computer. I’ll start by giving some background knowledge.

Three years ago, at our lab we had the need to write a Single Display Groupware (SDG). Let us temporarily forget about Multitouch tabletop and only focus on traditional mouse and keyboard.

What if multiple mice and keyboard are connected to the same computer. For historical reasons, contemporary operating systems natively support only one mouse and keyboard. I am not saying you cannot connect more mice and keyboard to your computer. Of course you can, but the OS treat them in the same way. For SDG based on mice and keyboards, one problem we are facing is how to discriminate one mouse/keyboard from another.

Let’s talk about mouse and keyboard separately in the following sections.

1. How to handle Multiple mice?

At that time, we did not think of implementing our own solution. We found the “SDG Toolkit” (http://grouplab.cpsc.ucalgary.ca/cookbook/index.php/Toolkits/SDGToolkit) from Saul Greenberg’s lab at the University of Calgary. Saul Greenberg is a big name in HCI. Some years ago in their group they did research in SDG, so they developed the toolkit. The library was quite old and only supports Microsoft .NET 2.0. Later on, I also found the Microsoft Multipoint SDK (http://www.microsoft.com/multipoint/mouse-sdk/) which is also capable of handling multiple-mice. Of course, here I mean handling multiple-mice within the application level, not at the OS level. Both solutions are only for Windows. In order to have it for other platforms, there is another C library called ManyMouse (https://icculus.org/manymouse/) which works on all three major OS’s. There is also a Java port of it.  The Java-based Multitouch Framework Mt4j also uses ManyMouse for simulating multiple touch.

Until now, you see that handling multiple mice input seems to have many alternative solutions. Then, how about keyboards?

2. How to handle multiple keyboards

SDG toolkit actually also support multiple keyboard for Windows. In Windows, you can of course make your own library by following the approach described in this article : http://www.codeproject.com/Articles/17123/Using-Raw-Input-from-C-to-handle-multiple-keyboard .

If you are looking for something for another OS, e.g. in Java. Unfortunately I did not find an existing solution. Of course, you are not possible to find a pure Java solution, because this involves handling low-level input.

I was actually inspired by the article I mentioned previously. I think it should not be difficult to make my own library if I am able to get the low level input of the operating system. I discovered HID API (http://www.signal11.us/oss/hidapi/) which allows an application to interface with USB and Bluetooth HID-Class devices on any OS platform. There is also a Java port of this library called javahidapi (https://code.google.com/p/javahidapi/).

I then started building my own library which is named “ManyKeyboard” with this Java api. It is not difficult. I made the source code available in my BitBucket repository  (https://bitbucket.org/nanli/manykeyboard/src). If you are interested, you can have a try, there is a TestManyKeyboard.java file. Just run it.

What I did to write this library was the following:

1. Read HID specifications and find the usage page of Keyboard device (usage page = 6)

2. Connect to all detected keyboard (with usage page =6 ).

3. Get the input report from the keyboard. An input report is the binary data of your USB device. For keyboard, you can get which key is pressed and released.

4. Fire the corresponding event.

In order to use this library, you can just create a class which extends ManyKeyEvent Listener, and initlalize the library in the following sequence.

keyboardManager.initializeLibrary();
keyboardManager.getKeyboardDevices();
keyboardManager.openKeyboardDevices(false);
keyboardManager.readKeyboardDevices();
keyboardManager.closeKeyboardDevices();

There is an example application in the repository. I already tested it on my Mac.

Summary

I created a Java lib called ManyKeyboard to handle multiple keyboard input. From now on, in order to develop an SDG application, you can do it with Java on any platform. Suppose you have a multitouch tabletop application and you want to use physical keyboard instead of onscreen keyboard, considering its lack of tactile feedback. Here is the solution.

UI design and Fitts Law

Fitts’ law is one of the most important law for aiding user interface design. It provides a tool for predicting the time required to reach a target, given the size of the target and the distance to it.

Basically it describes the bigger and closer a target is, the faster you can grab it. That being said, the time required to reach a target is proportional to the size of the target, and inversely proportional to the distance to the target. Fitts law is widely applied in user interface design.

For example, the Ribbon interface office button of Microsoft Word is designed to be large, so as to be reached easily.

图像

The Chrome tab is located at the top, making it easy for a user to choose a tab (Here, the distance to the tab can be seen as infinity, because your mouse can not move beyond the border of the screen). Unfortunately this only applies to Windows, because on a Mac, you have the menu bar on top. So Chrome actually leaves some blank space between the tab and the menu bar, so that users would not click on the menu bar accidentally, while their real aim is to switch a tab. Although Mac OS is generally speaking user friendly, and the menu bar does provide unified user experience, but I the sacrifice on Fitt’s law really make me very sad.

图像

Another case where Mac OS does not apply Fitt’s law is the close/minimize button for each window. The buttons are designed to be very small and round, making them very hard to click.  I don’t know why Apple never change the way the present the close/minimize buttons, maybe due to historical reasons. But this again makes me very disappointed.

304723_04

Actually, Mac OS is not always forgetting about Fitt’s law. For example the dock, and the Mission control and hot corners (infinite distance) are all good examples of appying Fitt’s law to UI design.

dock-de-Mac Lion_Mission_Control

Similar to the close/minimize button on Mac OS, it seems that Apple bring the violation of Fitts law to iOS as well. Whenever you want to delete or close an app on an iOS device. You often see these small round buttons on the top-left corners.

ios4-multitasking-close-app

You have to click the small button with your finger in order to close/delete an App. This really gives frustrating user experience to me. Sometimes I need to tap several times to hit the button.  I often ask. If Apple thinks 4inch is the perfect size of a mobile phone for human’s hand to hold and manipulate, if they think the thumb-sized application icons are perfect to hit with thumb. Well, all these are kind of true due to ergonomics. Why do they think the small close button can be tapped effortless?

Fortunately, Apple just release iOS 7 last night. My colleague installed it on his device and showed it to me. I find the this Jonathan Ive designed system really fixed the problem. Now you can kill an application by swipe it with your finger.

howtocloseapps1

(GIF Source here: http://www.cultofmac.com/231322/how-to-close-apps-in-ios-7-gif/)

Truly speaking, similar features are already available for Android devices and Jailbreaked iPhones. But now Apple make it officially. This is an “exciting news”!  It is actually quite difficult for Apple to admit something they designed are flawed, but this time. Jonthan did a good job.

Anyway, iOS and Mac OS are far better than Windows and Android in terms of user experience. But they can still can do even better, I believe.

Paper Review: Anatomy of the Unsought Finding. Serendipity: Origin, History, Domains, Traditions, Appearances, Patterns and Programmability

Today I read a paper which was published in 1994, titled “Anatomy of the Unsought Finding. Serendipity: Origin, History, Domains, Traditions, Appearances, Patterns and Programmability” by Pek Van Andel, a Dutch researcher. The reason why I read this paper is because I want to deeply understand the term serendipity, which is part of my research theoretical foundations. Now I am going to review and summarize this paper.

The contribution of this paper is as follows:

1. Definition of serendipity: the art of making an unsought finding.

2. Origin of the word: Jan. 28 1754 by Horace Walpole. He read a persian fairy tale called “The Three Princes of Serendip” — three princes were always making discoveries by accident and sagacity of things that they were not in quest of.  And he called this phenomenon “serendipity”.

3. Actually this paper is mainly about serendipity of discovery in four domains:

(1) Science (discover something new and true) (2)Technology (new and useful ) (3) Art (new and facinating) (4)Daily life . However, how true/ usefu/fascinating can not be proved in one day, maybe in the future.

4. The author discribminate three appearances of serendipity.

(1) Positive serendipity: A surprising fact or relation is seen and followed by a correct abduction, for example, the discovery of X-ray

(2) Negative serendipity: A surprising fact or relation is seen but not investigated by the discoverer, Columbus’s New Word’ for example.

(3) Pseudoserendipity: To discover, invent, create something you were looking for in a surprising way, Fleming discovered penicillin after he had discovered lysozyme.

The author also identify three kinds of reasoning. Deduction, induction and retroduction (abduction). Deduction proves that something must be; Induction shows that something actually is operative; Abduction merely suggests that something may be. Its only justification is that from its suggestion deduction can draw a prediction which can be tested by induction, and that, if we are ever to learn anything or to understand phenomena at all, it must be by abduction that this is to be brought about.

5. Patterns of serendipity

The author summarized 17 patterns of serendipity. I will not list all of them, just a few: Analogy, one suprising observation, repetition of a surprising observation, successful error, etc.

6. In practice, when serendipity plays a role, this role is normally secondary (supporting) but essential. Several studies indicate that commercially successful innovations for example are for about eighty percent answers to an already pre-existing and known problem, like the “pill”, but in the remaining twenty percent, it appears that something was discovered before there was a demand for it, like X-rays.

7. Can we programme serendipity? Serendipitious luck may come unexpectedly, but it does so only in a mind “prepared” by previous interest, thought and/or experience, as in the examples of pseudoserendipity, e.g. Fleming. The very moment we can programme is, that, if the unforeseen happens, the system alerts the user and incites him to observeand act by himself by trying to make a correct abduction of the surprising fact or relation. And I can ask the programme to specify as far as possible the conditions of the unexpected fact or relation, for example: is it incidental or structural? Thinking of a brainstorming support interface, I think this conclusion will help.

Making flat table interactive with Kinect and a projector

Microsoft Kinect is more than a game device, with the help of the embedded depth sensor, one can turn any flat table to an interactive multitouch surface. I made it yesterday. Just hang it for more than 1 meter above the table, and project your interactive content onto the table. That’s all for the hardware part.

For the software, you have to use OpenNI(or other Kinect hacks such as freenect), OpenCV to get your touch finger blobs,  this needs some programming.  You have to fire TUIO events when touches are detected to a multitouch-enabled application. That’s it. For the application, I use MT4j for a demo.

Building against MSVC2005 toolset using MSVC2010

Visual studio 2010 has more new features and nicer UI than the 2005 version. I would love to move to the new platform, but unfortunately the project that I am working on uses some non-opensourced  C++ library, which was built agains MSVC2005. When I tried to upgrade the whole project to VS2010, it simply didn’t work.

A good thing is that VS2010 support the so called “native multi-targeting”, which allows you to build your project against an earlier version of the platform toolset. To enable this, you just right click the project in VS2010, and open Property, you will find the following,

v100 means that the project will be built against MSVC2010 toolset, there is one more option in the list, which is v90, the MSVC2008 toolset. It’s good that we find this possibility, but on the other side, we are sad that there is no v80 option, since our project was originally a VS2005 project. I searched for some information on the internet, and find this guy’s blog (
http://blogs.msdn.com/b/vcblog/archive/2009/12/08/c-native-multi-targeting.aspx
), following his explanation, I navigate the windows explorer to the directory (C:\Program Files\MSBuild\Microsoft.Cpp\v4.0\Platforms\Win32\PlatformToolsets) and you will find this,

I created another folder called v80, which will include the same structure as v90 and v100 do. So in the newly created v80 folder I created two files ”Microsoft.Cpp.Win32.v80.props”  and “Microsoft.Cpp.Win32.v80.targets”.

The content of the first file is this,

<Project xmlns=”
http://schemas.microsoft.com/developer/msbuild/2003
“>

<Import Project=”$(VCTargetsPath)\Platforms\Win32\ PlatformToolsets\v80\ImportBefore\*.props”Condition=”Exists(‘$(VCTargetsPath)\Platforms\Win32\PlatformToolsets\v80\ImportBefore’)” />

<PropertyGroup>

<PlatformToolsetVersion>80</PlatformToolsetVersion>

<VCInstallDir>$(Registry:HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\VisualStudio\8.0\Setup\VC@ProductDir)</VCInstallDir>

<VCInstallDir

Condition=”‘$(VCInstallDir)’ == ””>$(Registry:HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\VisualStudio\8.0\Setup\VC@ProductDir)</VCInstallDir>

<VSInstallDir>$(Registry:HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\VisualStudio\8.0\Setup\VS@ProductDir)</VSInstallDir>

<VSInstallDir

Condition=”‘$(VSInstallDir)’ == ””>$(Registry:HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\VisualStudio\8.0\Setup\VS@ProductDir)</VSInstallDir>

<FrameworkDir

Condition=”‘$(UseEnv)’ != ‘true’”>$(Registry:HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\.NETFramework@InstallRoot)</FrameworkDir>

<FrameworkDir

Condition=”‘$(FrameworkDir)’ == ””>$(Registry:HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\.NETFramework@InstallRoot)</FrameworkDir>

<FrameworkSdkDir

Condition=”‘$(UseEnv)’ != ‘true’”>$(Registry:HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SDKs\.NETFrameWork\v2.0@InstallationFolder)</FrameworkSdkDir>

<FrameworkSdkDir

Condition=”‘$(FrameworkSdkDir)’ == ””>$(Registry:HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SDKs\.NETFrameWork\v2.0@InstallationFolder)</FrameworkSdkDir>

<FrameworkSdkDir

Condition=”‘$(FrameworkSdkDir)’ == ””>$(Registry:HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Microsoft SDKs\.NETFrameWork\v2.0@InstallationFolder)</FrameworkSdkDir>

<FrameworkVersion

Condition=”‘$(UseEnv)’ != ‘true’”>v2.0.50727</FrameworkVersion>

<Framework35Version

Condition=”‘$(UseEnv)’ != ‘true’”>v3.5</Framework35Version>

<ExecutablePath

Condition=”‘$(ExecutablePath)’ == ””>$(VCInstallDir)bin;$(VCInstallDir)PlatformSDK\bin;$(VCInstallDir)PlatformSDK\common\bin;$(VSInstallDir)Common7\Tools\bin;$(VSInstallDir)Common7\tools;$(VSInstallDir)Common7\ide;$(ProgramFiles)\HTML Help Workshop;$(FrameworkSDKDir)bin;$(FrameworkDir)$(FrameworkVersion);$(VSInstallDir);$(SystemRoot)\SysWow64;$(FxCopDir);$(PATH);</ExecutablePath>

<IncludePath

Condition=”‘$(IncludePath)’ == ””>$(VCInstallDir)include;$(VCInstallDir)atlmfc\include;$(VCInstallDir)PlatformSDK\include;$(VCInstallDir)PlatformSDK\common\include;$(FrameworkSDKDir)include;</IncludePath>

<ReferencePath

Condition=”‘$(ReferencePath)’ == ””>$(FrameworkDir)$(FrameworkVersion);$(VCInstallDir)atlmfc\lib;</ReferencePath>

<LibraryPath

Condition=”‘$(LibraryPath)’ == ””>$(VCInstallDir)lib;$(VCInstallDir)atlmfc\lib;$(VCInstallDir)atlmfc\lib\i386;$(VCInstallDir)PlatformSDK\lib;$(VCInstallDir)PlatformSDK\common\lib;$(FrameworkSDKDir)lib;$(VSInstallDir);$(VSInstallDir)lib;</LibraryPath>

<SourcePath

Condition=”‘$(SourcePath)’ == ””>$(VCInstallDir)atlmfc\src\mfc;$(VCInstallDir)atlmfc\src\atl;$(VCInstallDir)crt\src;</SourcePath>

<ExcludePath

Condition=”‘$(ExcludePath)’ == ””>$(VCInstallDir)include;$(VCInstallDir)atlmfc\include;$(VCInstallDir)PlatformSDK\include;$(VCInstallDir)PlatformSDK\common\include;$(FrameworkSDKDir)include;$(FrameworkDir)$(FrameworkVersion);$(VCInstallDir)atlmfc\lib;</ExcludePath>

<NativeExecutablePath

Condition=”‘$(NativeExecutablePath)’ == ””>$(ExecutablePath)</NativeExecutablePath>

</PropertyGroup>

<Import Project=”$(VCTargetsPath)\Platforms\Win32\ PlatformToolsets\v80\ImportAfter\*..props”Condition=”Exists(‘$(VCTargetsPath)\Platforms\Win32\ PlatformToolsets\v80\ImportAfter’)” />

</Project>

and in the second file,

<Project ToolsVersion=”4.0″ xmlns=”http://schemas.microsoft.com/developer/msbuild/2003″&gt;
<Import Project=”$(VCTargetsPath)\Platforms\Win32\ImportBefore\*.v80.targets” Condition=”Exists(‘$(VCTargetsPath)\Platforms\Win32\ImportBefore’)” />
<UsingTask TaskName=”VCMessage” AssemblyName=”Microsoft.Build.CppTasks.Common, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a” />
<PropertyGroup>
<PlatformPrepareForBuildDependsOn>PlatformToolsetPrepareForBuild;$(PlatformPrepareForBuildDependsOn)</PlatformPrepareForBuildDependsOn>
</PropertyGroup>
<!– *******************************************************************************************
PlatformToolsetPrepareForBuild target
******************************************************************************************* –>
<Target Name=”PlatformToolsetPrepareForBuild” DependsOnTargets=”_DetermineManagedStateFromCL;$(PlatformToolsetPrepareForBuildDependsOn)”>
<!– If the project is targeting any other CLR version than v2.0, v3.0, v3.5, issue a warning –>
<VCMessage Condition=”‘$(ManagedAssembly)’ == ‘true’ and
‘$(TargetFrameworkVersion)’ != ‘v3.5′ and
‘$(TargetFrameworkVersion)’ != ‘v3.0′ and
‘$(TargetFrameworkVersion)’ != ‘v2.0′ and ‘$(DesignTimeBuild)’!=’true’ “
Code=”MSB8002″ Type=”Warning” Arguments=”$(PlatformToolset);$(TargetFrameworkVersion)”/>
</Target>
<Import Project=”$(VCTargetsPath)\Platforms\Win32\ImportAfter\*.v80.targets” Condition=”Exists(‘$(VCTargetsPath)\Platforms\Win32\ImportAfter’)” />
</Project>

Then I cleaned the original project and rebuild all—- it works. Now I can keep using this  IDE to enjoy its new features. Good:D