Random Words My Chosen

博客荒废了2个月,不忍让时间悄然飞逝,终于鼓起劲把博客重新整理下。其实不写博客还有另外一个原因,就是我习惯了用Evernote来记笔记。Evernote用起来是很方便,特别是做些文字剪辑。但是用久有些缺点还是很明显,如没有层次结构,用标签管理,如果标签没有规划好,就很容易乱了。得经常需要整理,而我又疏于整理,最后只能越来越乱了。确实不如wiki清晰,且页面间不能互相连接是个缺憾。

说回整理博客,趁这个机会实现了个以前很想实现的功能,就是随机显示不同的副标题(见右上角)。这样就可以把一堆格言名句之类东西扔进去每次访问随机显示一条出来。一开始写在主题文件上面,觉得这样写很丑,便想写成wordpress的插件。仔细了解一番发现写成插件也并不复杂。 (更多…)

插入!数学公式测试,附上一个很SB的Java程序

实际上我不喜欢插入这个词!

在网页上嵌入数学公式,之前已经在wiki上试过,尝试了jsMathmathJax。这两个都不是在服务器是渲染Latex代码,而是用javascript在客户端渲染,而且渲染出来的不是图片而是文本,也就是说可以复制粘贴到文本编辑器上,不知这个算不算优点,好处节省下带宽,但实际在IE8上可以说又慢又卡,chromium还可以接受但下标有点错位,也许是我配置的问题,对FireFox的支持是最好的。但是为了获得最佳的显示效果客户端必须要安装某种最佳字体,选择mathJax会自动下载该字体。点击这里看下mathJax的效果。相对来说mathJax比jsMath更方便些。

总的来说,用js还是有点麻烦,所以回到传统考虑在服务器上生成图片。这个可以自己架设,也可以用一些公共服务,比如说forkosh.dreamhost,更多的参考这篇文章
forkosh的使用十分简单,只需在http://www.forkosh.dreamhost.com/mathtex.cgi?”后面加入Latex代码。如加上e^{i\pi}+1=0,即http://www.forkosh.dreamhost.com/mathtex.cgi?e^{i\pi}+1=0”,出来的就是欧拉恒等式

可以用\color 来指定颜色,如\color{red}\frac{\int_{-\pi}^\pi \sqrt{1+\cos^2{t}}dt }{2\pi}

出来的效果是:

更多forkosh参考这篇文章,和forkosh主页,forkosh提供一个很实用的practice box,编辑时候用来测试很方便。

话说贴图片的时候还遇到不少麻烦,ShadowBlue这个主题为图片添加了样式——渐变的边框和白色背景,在内嵌图片到文本的时候相当不和谐。但自己改了css后,发现居然不生效,费了我半天时间改css和半天时间学习css的优先级。后来发现居然是我把css代码复制了多一份,改的时候是改前面的然后又被后面的改覆盖了,不过总算搞定了。

发现以前的一篇文章来测试数学公式,倒是挺合用的。

很SB的Java程序在此

SB

其实这个程序的行为很简单,就是用java来控制鼠标,确切的说应该是用java来控制鼠标的运动轨迹。想用java来控制鼠标并不是一件困难的事。因为java本身提供了一个类Robot。在帮助文档中对Robot类是这样描叙的:此类用于为测试自动化、自运行演示程序和其他需要控制鼠标和键盘的应用程序生成本机系统输入事件。Robot 的主要目的是便于 Java 平台实现自动测试。

虽说字都看的懂,不过什么意思还真有点不明白。不过这个程序我们主要用到的就是Robot类里的mouseMove(int x, int y)方法。这个方法可以将鼠标移动到屏幕上坐标(x,y)的位置上。通过这个方法就可以来控制鼠标的运动轨迹。比如说,要让鼠标画上图的轨迹。

那么只需让鼠标跟着这些轨迹移动就可以,具体的实现可以逐个像素改变y坐标的值,并实时计算x的值。每次更新都调用一次Robot的实例化方法mouseMove(x, y),这样就可以实现鼠标指针沿轨迹移动的效果。

另外也可以一次性运算好所有点。并保存成Point[],之后每一次画轨迹,只需按顺序历遍Point[]上的值。代码大致如下:

for(int i = 0 ; points.length ; i++){

           robot.delay(speed);

           robot.mouseMove(points[i].x, points[i].y);

       }

接下来,我们再来看下如何画出上图的轨迹。首先,我们看下红色的轨迹,似乎可以很牵强地把它看成字母’S’,但是实际上它是一条正弦函数取区间的曲线。当然也可以说是余弦函数。这不是重点,重点是如何这条曲线映射到屏幕上的实际位置。无非通过缩放、旋转、移位。知道曲线和横坐标距离是。而相对应于屏幕上的距离。所以可以知道曲线放大的倍数就是。显示在屏幕上的曲线是旋转的。也就是原本曲线的y变成屏幕上的x。而x变成屏幕上的y。在加上偏移量m。就可以算出屏幕上x,y的值了。让i为正弦函数的变量,取
可知y每增加一个像素,便增加

这样就定义红色曲线的轨迹方程。当然屏幕上的点是离散。只能是整数。需要对sx的值取整,这个调用Math.round(double d)就可以实现四舍五入,另外d也是这轨迹上所有离散的点的个数。

接下来看蓝色的轨迹,很明显是条直线。其方程也一目了然。

最后看下橙色的轨迹,其实就是对正弦函数取绝对值得到的曲线。实际上,是可以不用进行正弦计算的,因为我们已经计算好保存在sx里了。利用sx我们可以得到橙色轨迹的方程如下,当然这里是建立在的前提下。

现在就可以写出生成所有轨迹的点的集合的代码了,具体如下:

final int m = 150;// 上下的边距
final int xpoints[];// 保存x坐标.因为y是递增的,规律简单,可以不用保存
final int dist = 200;// 两条曲线间的距离
final int y1 = m,
y2 = Toolkit.getDefaultToolkit().getScreenSize().height - m;
final int d = y2 - y1;
final double n = (y2 - y1) / (2 * Math.PI);
final int x1 = (Toolkit.getDefaultToolkit().getScreenSize().width - dist)
                / 2 - (int) Math.round(n);
final int x3 = x1 + dist;
xpoints = new int[d * 3];// 点的总量是d*3;
double i = -Math.PI;
int nn = 0;
while (nn < d) {
        xpoints[nn] = (int) Math.round(x1 + n * Math.sin(i));// 红色轨迹
        xpoints[d + nn] = x3;// 蓝色轨迹
        xpoints[2 * d + nn] = x3 + Math.abs(xpoints[nn] - x1);// 橙色轨迹
        nn++;
        i += 1 / n;
}

接下来就是主角登场了。

final int speed=5;//休眠时间,就是是鼠标运动的速度
     try {
        Robot r = new Robot();//实例化一个Robot对象
        int tmpY= 0 ;
       while(true){
           if(nn>=d&&nn<=2*d)
        //为保持鼠标移动速度的一致,直线的距离要比两条曲线的距离短,而实际的关键点是一样多.所以每个关键像素的
           //停留时间都要缩短一下,当然1/2是不准确的估计.见@http://dourok.info/2010/08/316/最上面的红色公式.
               r.delay(speed/2);
           else
               r.delay(speed);
        r.mouseMove(xpoints[nn](tmpY+y1));//mouseMove移动的是绝对位置而不是相对位置
        tmpY=(tmpY+1)%(d);
        nn=(nn+1)%xpoints.length;//让鼠标不断循环的画轨迹
       }
    }catch (AWTException ex) {
        ex.printStackTrace();
    }

程序到此就完成了,直接放在main方法里就可以运行。请注意,程序无法退出,并且鼠标无法操作,要怎么结束呢?没错,任务管理器。嗯,确实挺无聊的。当Robot非但不无聊,还很强大,顺便一提delay()其实就是睡眠当前线程。Thread.sleep()一样。不过注意delay()里的参数是int。而且如果不在 0 到 60,000 毫秒的范围内,就会抛出错误。

还有另一个方法setAutoDelay()是设置Robot 在生成一个事件后睡眠的毫秒数。貌似该程序更适合用这个方法。如果问我为啥不用,我只能说,我写完程序后才发现。懒得改了。

Robot的强大还在于它不只能控制鼠标,键盘的任意行为,还有

public BufferedImage createScreenCapture(Rectangle screenRect)这个方法用来获取屏幕在Rect区域内的图像。基本上有这个方法,做抓屏软件就不是什么问题了。

public Color getPixelColor(int x,int y)这个方法是返回给定屏幕坐标处的像素颜色。是不是感觉更按键精灵的功能很相像。

可以得到当前屏幕的图像,又可以控制鼠标,键盘的行为,实际上,Robot就是经常被用来做远程操控软件的。在游戏开发中Robot也可以用来做鼠标强制居中,对这个类也是停留在刚刚认识的阶段。

程序在此!

ProGuard混淆丢掉空循环

项目正要发布时,我用proguard打了个混淆包,想不到运行的时候出错了。proguard是Netbeans6.9 J2ME插件自带的,版本号是4.4。

无奈只好debug加反编译,发现居然混淆后的代码里,我用来挂起线程的空循环语句,所谓的busy-waiting loop被去掉了

原代码大概如下:

boolean a = false;

new Thread().start

while(a);

混淆后的代码while(a);这句已经不见了
加上个括号也不行

boolean a = false;

new Thread().start

while(a){ }

必须做些操作,循环才会正确运行。

boolean a = false;

new Thread().start

while(a){

System.out.print("");

}

想必是proguard给优化掉,Google了一下居然被我找到了一段Troubleshooting(原文地址),摘录如下:
(更多…)

如何为MTK平台添加新模块

包含源码的第三方库

以添加一个TTS模块为例,可以按如下步骤添加:

  1. 把TTS的源码包复制到你的MTK软件系统根目录下,以让TTS的源码都在TTS目录中
  2. 在make目录下新增一个tts目录,在tts目录下添加4个新文件,分别是,tts.def、tts.inc、tts.lis、tts.pth。tts.def文件的内容需要根据内容来修改,其他3个文件中加上源文件及其目录、头文件目录即可。
  3. 在REL_CR_MMI_<project>.mak 中加上如下语句
    CUS_REL_SRC_COMP += tts
  4. 把MTK工程remake一下,若没有错误,tts模块就成功加上去了。
  5. 如果要为Modis模拟器添加该模块,须进入到Modis目录,在createMoDIS.ini文件中,[GLOBAL_SETTINGS]下,追加
    enable_libs += tts
    createMoDIS.ini会在createMoDIS.pl中加载
  6. 不包括源码的第三库

添加一个无源码的库,如xxx.lib,可按照下面步骤:

  1. 在MTK软件系统根目录中新建一个xxx文件夹,把xxx.lib放在里面
  2. 在make\\Option.mak里增加下面几行,ifeq语句不是必要。
    ifeq ($(strip $(XXX_SUPPORT)),TRUE)
    COMPOBJS += xxx\\xxx.lib
    CUS_REL_OBJ_LIST += xxx\\xxx.lib
    endif
  3. 有 头文件,要将头文件路径加入,用CUSTOM_COMMINC如:
    CUSTOM_COMMINC += ..\..\inc
  4. 如果加了XXX_SUPPORT判断,须在<customer>_<project>.mak文件中添加,并初始化为 TRUE:
    XXX_SUPPORT = TRUE;
  5. 修改完成后,remake就可以将新模块添加到工程里了。
  6. 关于 ifeq ((XXX_SUPPORT)),TRUE)语句的意思是如果XXX_SUPPORT的值为TRUE则继续执行。strip函数详见这里

Modis模拟器不能调用该库,Modis模拟器调用的库要经过VC编译。

生成自己的Lib库

(更多…)

从GBK到Unicode的中文字符映射

前言

最近在做MTK开发,需要在程序中将GBK编码的文本文件实时转换为unicode编码,因为MTK只认Unicode。经尝试网上提供的mmi_chset_convert函数在我手上的SDK里没有用,很奇怪这个函数的只是调用了memcpy。无奈之下只能自己动手实现转换,也好趁这个机会摸清以前一直一知半解的字符编码。

说到字符编码,第一误解就是字符集(character set)和字符编码(character encoding)的混淆。以前经常把所有名词都当成字符编码(encoding),比如我就把GB2312叫成编码,实际上GB2312应该是字符集, 而它用的编码方式应该叫做EUC-CN。对于字符集跟字符编码的区别还是很难理解的(可看维基百科这里这里这里),我也模糊,再说下我的理解,比如说思密达们用的字符集是KS X 1001,而他们的编码方式也是EUC,不过是叫做EUC-KR。关于EUC编码方式,实际上就是对于ASCII字符用一个字节(8bit)表示,高位(第一位)为0来表示它是 ASCII字符,而其他字符用两个字节表示(16bit),且每个字节加上0xA0(16进制),也就将它们的高位置为1,以跟ASCII字符区分开来(后面在我的程序里就可以看到这个应用)。关于这个问题可再参考Blogjava上的两篇系列文章,[1][2]

当然如今把GB2312等同于编码了也不会有任何问题了。Html文档头经常出现的 charset=utf-8 对此贡献不少,这里的charset应该是指encoding,再比如说charset=gb2312实际上指的就是“EUC-CN”(强调一下utf-8、iso-8859-1都是字符编码,unicode才是字符集)。所以关于标题《从GBK到Unicode的中文字符映射》,实际上应该叫做《GBK到UTF-16(UCS2)的中文字符映射》,

GBK

GBK即汉字内码扩展规范,是“国家标准扩展”三个词的拼音缩写。具体可参考维基百科

GBK既是字符集也是字符编码(够讨厌的吧…)[2]。不过这不重要,解决问题的关键是摸清GBK的编码方式,才能找到GBK到Unicode的映射规律。在此贴下维基百科上的图片:

由上表可见,GBK编码主要将字符分为五个区域。

其中GBK/1、GBK/2就是GB2312的字符集,其编码跟GB2312的编码是一致的,所以说GBK是向下兼容GB2312。GBK/3、GBK4就是GBK新增的汉字,许多繁体字、偏僻字都集中在此。但GBK/4中并不是全都是汉字,或者是不存在Unicode字符集中的汉字,经我统计实际上只有8059个汉字是在Unicode中存在的。剩下的GBK/5跟GBK/1一样存放都是特殊符号。

Unicode

(更多…)

在Netbeans上配置Android开发环境

NBAndroid

突发奇想要看看Android应用程序的开发,在网上找了些文章,发现android的开发环境大多是Eclipse+ADT,其实在netbeans上也是可以的。有个netbeabs插件叫NBAndroid,如果想在Netbeans上开发Android应用第一步就是要安装它,下面是NBAndroid的项目主页
http://kenai.com/projects/nbandroid

安装与设置

要安装NBAdroid,推荐的方法是在NetBeans中注册NBAdroid的更新中心(Update Center),具体的步骤是:

  • 打开工具(Tools )-> 插件(Plugins) -> 设置选项卡(Setting)
  • 点”添加”按钮将这个链接http://kenai.com/downloads/nbandroid/updatecenter/updates.xml加进去,改个名字,确定。
  • 转到可用插件选项卡(Available Plugins),找到Android插件,安装。出现验证警告点继续就可以了。


添加NBAndroid更新中心


安装NBAndroid

安装的步骤很简单,下载后将压缩包解压,然后把所有*.nbm的文件导入到netbeans便可。在netbeans中添加插件的方法也说一下,在”菜单栏” -> 工具 -> 插件 在插件页面的”已下载”选项卡中可找到按钮”添加插件”,这个按钮便是可以用来添加nbm文件,如图1所示

接下来,指定Android SDK的位置,方法:”菜单栏” -> 工具 -> 选项,点击”Android”标签页。就可以看到类似下面的界面:

选择SDK的目录便可。

如果还没有Google Android SDK 的话要先下载Android SDK,下载页在这里。官方的安装说明在这里(英文)。(网站已被墙,推荐Google 搜索GappProxy)安装SDK的步骤要多一些,将下载后的压缩包解压到你要放的位置。运行SDK Setup.exe应该会看到下面的界面,记得在win7下得用管理员权限运行。

图3

我这张图是更新后截的,没更新前只有Android SDK Tools,revision 6一个项。嗯,没错更新服务器也被墙了,可在setting了设置Http 代理服务器,因为GappProxy对Https的支持不好,下图那个选项也打上勾。


图4

更新好之后先别急着关掉,还要新建一个设备,选择Virtual Devices,单击”New”,建好之后就可以重新回到NetBeans了。

图5
(更多…)

Java ME通用Logger包和控制台

写在前面

这是一个JavaMe的通用轻量级Logger系统和控制台程序,轻击这里下载logger源码,把它拉到你的项目里面去便可,要看下例子可以再轻击这里,还有效果图在这

正文

OK,正文了。我写Java Me程序的时候很多次程序都是自我感觉良好在模拟器上跑起来也没问题,但一到真机就卡壳了。而且,在真机上跑又不像在电脑上开发一样有个控制台可以打印信息,有时要在真机上获得一系列错误信息那是相当麻烦。我曾经试过,调用InputStream的read(byte[]b,int offset,int len)方法,居然可以最后一字节没被读出来;用new String(byte[] b , “gb2312″)来转换编码时,居然最后一个字节会丢失;还有用Connector来得到FileConnection时,如果将模式设置为“只读”直接程序崩溃,等等,好多。真是苦不堪言。恩,好吧,我承认我的机器是MTK系统滴。如果说ME程序员是IT民工中的搬运工,那么给MTK写ME程序的就是那枚扮演烈日下搬砖头的角色。所以说如果能有一个通用的控制台程序那就显得相当有用了,简直就是给ME程序员穿上滑轮鞋。

恰好,近日在看Fire2[1]时,里面刚好有个控制台,还有个日志系统。不过Fire2的控制台是基于它自己的UI控件的,不具备通用性,而且效率不行,打印信息一多严重拖慢系统程序。于是我自己用Canvas重新实现了控制台,并将Fire2中的日志系统提取出来做了点修改,跟我的控制台打包成一通用的日志系统logger包。

该日志系统有三个类一个接口组成。

Log是在Fire2里实现好的,有一系列的静态方法,包括添加和设置Logger,还有一系列记录消息的方法,Log里面的消息四个级别,分别为Info、Warn、ERROR、Debug。Log对象默认实现一个Logger,这个默认的Logger就是将消息打印在控制台(System.out.println())。

Logger 是一个接口只有一个方法

1
public void println(String txt , int level);

要自己实现logger只需实现这个接口便可,比如说把Log消息写文件里面去,发送到服务器等等。

Console就是控制台,是一个独立的全屏的界面,继承了Canvas,实现了Logger接口。将Log记录下来的消息绘制到屏幕上。考虑到一个Midlet只需要一控制台,又必须给Console传入Display参数,所以便按单例模式实现Console。

得到Console实例的方法有两个,getConsole(Display) 和getConsole()

但要注意一点,第一次得到Console对象时,必须先使用getConsole(Display),来为其传入Display对象。

显示Console只需调用showConsole(Displayable screen),传入的Displayable为调用显示控制台是的当前界面,从Console返回时会自动显示该界面。screen可以为null,当screen为null时Console无法返回。

一个使用控制台的例程可以像这样

Display dis = Display.getDisplay(this);
Console console = Console.getConsole(dis);
Log.showDebug = true;
Log.addLogDestination(console);
Log.logInfo("console already");
Log.logDebug(Console.getMemoryInfo());
try{
//一些可能抛出异常的操作
}catch(Exception e){
Log.logError("ERROR" , e);
console.showConsole(null);
}

Console还有个String getMemoryInfo()的方法,来得到当前虚拟机的内存信息。

ConsolePainter 是控制台画笔,负责把字符串绘制到屏幕上,ConsolePainter绘制字符串暂时还可以接受的,主要因为绘制的时候只有当前屏幕会显示到的字符串才会被绘制,具体留意下setTransition()。Console便是使用该类来绘制信息,同样的ConsolePainter实现了Logger接口,所以,也可直接在你的Canvas使用该画笔,来把Log消息直接绘制在Canvas上。

再来看下ConsolePainter的构造函数ConsolePainter(Canvas canvas, boolean autoclean),canvas为需要绘制画笔,ConsolePainter要获得Canvas的大小来布局字符串,绘制的时候需要在Canvas调用ConsolePainter.paint(Graphics g)。很多时候消息太多会超过一屏,要在canvas实现滚屏那显的没必要。将autoclean设置为true,当消息超过一屏时,旧的消息会被移除,以保证新消息可以显示在屏幕中。

最后

先来看下效果图先。这可是MTK真机上截的图哦。

现在Console的问题应该是多多的,可定制性几乎没有。不过我目前用起来挺顺手的,以后还会一直用它,发现问题到时再来改吧。

源码下载

[1].Fire2 是一款轻量级的J2ME UI库,可自定义主题,同时支持渲染xHtml/CSS,提供有xHtml浏览器组件。这里是它的项目地址