激光键盘软件源代码编译和修改指南

English Version: http://www.robopeak.net/blog/?p=332

I. 简介

RoboPeak 开源虚拟激光投影键盘设计的所有源代码已经发布在Github上。该源代码遵循LGPL许可。只要遵循LGPL许可的规范,您可以随意的使用或者修改本源代码。

本文旨在介绍如何在Windows以及MacOS平台上编译RoboPeak 开源虚拟激光投影键盘的信号处理软件。此外,也介绍了一些技术细节问题,帮助您理解代码并开发新的酷功能。

快速参考:

  • 如何在Windows上编译运行代码
  • 如何在MacOS上编译运行代码
  • 更多细节

II.  从源代码编译的理由

首先,从源代码编译允许您体验到我们为激光键盘开发的最新功能,这些功能并不会立刻在稳定版本中发布。您可以成为最早体验这些功能的人。

其次,如果您需要对我们的软件做出修改或者做改进。能编译源代码就是必经之路了。

此外,如果我们的信号处理软件无法在您的系统运行,那么在我们团队做出修正前,您可先尝试自己编译源代码来解决此问题。

III. 先要准备的

  • Windows

Windows XP 以及更高版本

Visual Studio 2010 (带有VC++包) 或者 Visual C++ 2010 express (更高的版本也可工作,但我们暂不作保证)

Git工具支持 (例如: msysgit)

  • MacOS

OS10.7 或更高版本 (我们使用OS10.8)

XCode 4.5 或者带有gcc支持的更高版本 (我们不使用 llvm-gcc进行编译)

GIT 工具(您可使用 macport or homebrew 来安装它)

除了上述的系统环境需求外,我们默认您具有基本的软件开发基础,例如:了解如何在Windows/MacOS上开发编译C++的程序,知道OpenCV是什么,GIT是什么。此外,您需要知道如何从github clone源代码

IV. 在Windows上编译运行源代码

STEP1: 从Github clone源代码

我们推荐您使用tortoise-git clone源代码到您本地的文件夹中,如下图例子那样;
tutorisegit_clone 或者直接基于如下命令行:

git clone https://github.com/robopeak/laserkbd.git

在Cl0ne完毕后,您应该看到如下的文件结构: cloned_source

STEP2: 在VS2010中编译

进入laser_kbd_neo 文件夹并打开VS项目文档:laser_kbd.sln:

vs2010

您只需要选择Release编译配置并开始编译即可。编译完毕后,您可以在 laser_kbd_neoRelease文件夹中找到编译好的可执行文件:laser_kbd.exe

vs_compiled

STEP3: 将必要的依赖文件复制并打包

上述编译产生的可执行文件需要其他依赖文件才能执行,并且这些依赖文件需要与可执行文件位于同一个目录。因此您需要将这些文件复制过来。我们推荐您创建一个新的目录,例如在代码根目录下建立一个output这样的目录,并将laser_kbd.exe以及下列文件夹、文件复制进来:

  • laser_kbd_neores 文件夹
  • sdkpackrefdll*.dll

最终的软件包应该看起来像这样: vs_released

大功告成!

现在您自己编译的信号处理软件已经可以工作了! win32_done

V. 在MacOS下编译源代码

STEP#1 Clone源代码

使用如下命令将Github的源代码clone至您本地的文件系统:

$ git clone https://github.com/robopeak/laserkbd.git

在clone完毕后您应该看到如下的文件结构

Shikais-MacBook-Pro:laserkbd csk$ ls
README.md laser_kbd_neo sdkpack

STEP#2 在XCode中编译运行

进入目录laser_kbd_neo/xcode, 打开项目文件LaserKeyborad.xcodeproj.

xcode_compile

您可以直接点击运行按钮就可以编译出可以执行的软件包了(Debug版本)

macos_compiled

VI. 实现细节浅析

1. 文件组织

本源代码文件按照如下的结构进行组织

<source root>
      +---- laser_kbd_neo/            <--- 所有的源代码、IDE用到的工程文档
      |          +---- ref/           <--- 第三方库的源代码
      |          +---- res/           <--- 软件所用到的图片、数据等文件
      |          +---- src/           <--- 信号处理软件自身的源代码
      |          |      +---- port/      <--- 平台相关的源代码
      |          +---- xcode/         <--- MacOS/xcode相关的源代码和项目文档
      |          |---- laser_kbd.sln  <--- Visual Studio 2010项目文档
      +---- sdkpack
                 +---- license_and_copyrights/   <--- 第三方库的许可协议和README文档
                 +---- ref/
                        +---- dll/               <--- 第三方库的预编译dll (win32)
                        +---- lib/               <--- 第三方库的预编译lib (win32)
                        +---- inc/               <--- 第三方库的头文件
                        +---- dylib/             <--- 第三方库的预编译dll (MacOS)

 

2. 如何将代码移植到其他平台下?

本信号处理软件在开发初期就考虑了高度可移植性,表现在:

1) 所有的核心处理逻辑都是平台无关的代码

2) 所有平台相关的代码都放在了目录 src/port 里

3) 在平台相关/平台无关代码之间有明确的接口作桥梁

4) 所有依赖到的第三方库也是高度跨平台的,例如: OpenCV

如果您打算将源代码移植到新的平台下,您需要为这个新平台实现一个新的移植层(port layer)。这个移植层至少需要提供如下功能:

  • 按键事件注入

当“键盘”按下后,往OS注入对应的键盘事件

  • 摄像头视频捕捉已经曝光控制

由于OpenCV本身不允许用户代码控制摄像头的曝光参数,因此移植层需要实现这个机制。

所有对平台相关代码的调用接口都定义在了src/port/common文件夹里面。如果您确定要开始移植工作,则应该从这些接口定义开始入手。

此外,您也可以参考目前Windows和MacOS上的移植层。

3. 如何修改键盘布局?kbd_layout

位于src/keyboard_emu/layout_provider.cpp 的代码控制信号处理软件内部的键盘布局信息。 (实际的虚拟键盘投射元件也需要做出修改).

通过修改 _key_mapper[] 描述数组,可以实现对软件中键盘布局的修改。

4. 如何实现在“按键”时播放声音提示?

该功能已经在Windows平台中实现.

由于播放音频的方法是与具体操作系统相关的,因此推荐将这个功能放在移植层里面实现。这里将举例说明如何在Windows上实现这个功能。

我们使用如下的Win32 api实现播放一段制定的wav音频:

BOOL sndPlaySound(
 LPCTSTR lpszSound,
 UINT fuSound
 );

在这个例子里,我们使用的音频文件叫做type.wav. 当用户“按键”后,windows就会播放这个声音:

在移植层中定义了接口OSKeyInjector::injectKeyEvents用于操作用户“按键”以后的事情. 可以从这里入手加入播放声音的功能:

如下是Windows平台中该接口的原始实现代码 (keyinjector_win32.cpp)

    virtual bool injectKeyEvents( const std::vector<KeyEventDesc> & intputlist)
    {
        if (!intputlist.size()) return false;

        INPUT * inputs = new INPUT[intputlist.size()];

        do
        {
            for (int pos=0; pos<intputlist.size(); ++pos)
            {
                inputs[pos].type = INPUT_KEYBOARD;
                inputs[pos].ki.wVk = intputlist[pos].keyval;

                if (intputlist[pos].type == KEY_EVENT_PRESSED) {
                    hasinputs = true;
                    inputs[pos].ki.dwFlags =  0;
                } else {
                    inputs[pos].ki.dwFlags =  KEYEVENTF_KEYUP;
                }

                inputs[pos].ki.time = 0;
            }

            SendInput(intputlist.size(), inputs, sizeof(INPUT));

        }while(0);

        delete [] inputs;

        return true;
    }

我们将它修改如下:

    virtual bool injectKeyEvents( const std::vector<KeyEventDesc> & intputlist)
    {
        if (!intputlist.size()) return false;

+        bool hasinputs = false;

        INPUT * inputs = new INPUT[intputlist.size()];

        do
        {
            for (int pos=0; pos<intputlist.size(); ++pos)
            {
                inputs[pos].type = INPUT_KEYBOARD;
                inputs[pos].ki.wVk = intputlist[pos].keyval;

                if (intputlist[pos].type == KEY_EVENT_PRESSED) {
+                    hasinputs = true;
                    inputs[pos].ki.dwFlags =  0;
                } else {
                    inputs[pos].ki.dwFlags =  KEYEVENTF_KEYUP;
                }

                inputs[pos].ki.time = 0;
            }

            SendInput(intputlist.size(), inputs, sizeof(INPUT));

        }while(0);

        delete [] inputs;

+        if (hasinputs && g_config_bundle.playsound) {
+            // play sound feedback
+            std::string soundfile = FILEPATH_RESOURCE_SOUND_FOLDER;
+            soundfile += "type.wav";
+            ::sndPlaySoundA( soundfile.c_str(), SND_ASYNC);
+        }

        return true;
    }

这样按键声音反馈功能就实现好了。您可以自行编译github的源代码体验一下:)

2 thoughts on “激光键盘软件源代码编译和修改指南”

Leave a Reply

Your email address will not be published. Required fields are marked *