Code Keyboard在BSD下的多媒体快捷键配置

在之前买了个Das Keyboard之后,这回为了在家里用搞了个Code Keyboard。
Code Keyboard自带一堆多媒体键,不过要让这些多媒体键发挥作用还要费些功夫。
刚插上去的时候,多出来一个键盘和一个鼠标设备:

ukbd2: <vendor 0x04d9 USB Keyboard, class 0/0, rev 1.10/1.10, addr 8> on usbus0
ums2: <vendor 0x04d9 USB Keyboard, class 0/0, rev 1.10/1.10, addr 8> on usbus0

作为一个键盘来说,有个鼠标设备还是很奇怪的,所以多半是用来给多媒体键的。Ports Tree里有个uhidd,https://wiki.freebsd.org/uhidd,可以用来处理这些多媒体键对应的hid事件。ukbd驱动不错,我们只要干掉ums驱动就可以了。为了这个,先配置uhidd让他干掉ums自己attach上去:

0x04d9:0x0169:0={
    detach_kernel_driver="NO"
}

0x04d9:0x0169:1={
    detach_kernel_driver="YES"
}

之后跑uhidd -h /dev/ugen0.7 (这里ugen0.7是这个键盘对应的ugen设备,-h启动HID类设备),就会发现/dev底下多了uvhid0。
跑系统自带的usbhidctl -f /dev/uvhid0 -l -a,然后按那些多媒体键,就能看见HID状态变化的事件,例如Volume_Increase从0变到1然后变回去之类。

之后,要让uhidd把这些事件翻译成键盘按键。在配置文件的0x04d9:0x0169:1那段里加一段:

    cc_keymap={
        Play/Pause="0x54"
        Stop="0x5a"
        Volume_Decrement="0x62"
        Volume_Increment="0x63"
        Mute="0x6f"
        Scan_Previous_Track="0x7a"
        Scan_Next_Track="0x7c"
    }

,之后用uhidd -o /dev/ugen0.7重新启动uhidd,然后再跑起一个xev,就会看见有键盘事件进来。-o参数启动Consumer Control类驱动,uhidd会参考cc_keymap映射表来映射那些事件。在uhidd.conf里列出了一些一般不会用的scancode,都可以拿来映射。

之后要把那些keycode映射到X的符号名上。xev收到的是keycode,上面指定的是scancode,映射的时候用xev里收到的。修改.Xmodmap,加上一些:

keycode 92  = XF86AudioPlay
keycode 130 = XF86AudioPrev
keycode 132 = XF86AudioNext
keycode 170 = XF86AudioStop
keycode 189 = XF86AudioLowerVolume
keycode 190 = XF86AudioRaiseVolume
keycode 207 = XF86AudioMute

在跑xmodmap .Xmodmap之后,xev里看见的应该就是类似于XF86AudioMute这样的符号名而不是光keycode了。

最后做一些对应这些符号名的快捷键,例如mpc next之类,就大功告成了……

本来uhidd应该自动启动,不过貌似不靠谱,我在/etc/devd/里加了codekbd.conf:

notify 100 {
    match "system"      "USB";
    match "subsystem"   "DEVICE";
    match "type"        "ATTACH";
    match "vendor"      "0x04d9";
    match "product"     "0x0169";
    action "/usr/local/sbin/uhidd -o /dev/$cdev";
};

这样uhidd就会自动启动了……

PS. 我在学校的Arch上试了一下,音量调整直接就能用……

implicit declaration又出来害人了

说把vps迁移到64位系统后,collectd不记数据了,rrdupdate直接crash……
调试发现是implicit declaration干的好事情……
rrdupdate.c用到了basename(),但是没有引用libgen.h,于是basename()是隐式声明的。
根据古老的c的规定,隐式声明的函数返回值被当作了int,而64位系统上int是32位的。
所以本来好好的char*的返回值就被当作了int,返回值的高32位被干掉了,指针直接就飞了……
其实是有编译警告的,但是who cares……
所以c代码都该直接当c++编译,好的c代码应该可以直接编译…… 不声明就用算是什么feature,简直是个bug……
另外其实上游已经修了这个bug: https://github.com/oetiker/rrdtool-1.x/commit/d0bd4217d9fb69db9f94363087936cf93fa9b4ea,不过修完之后没有发新release,于是下游也没人管,毕竟谁喜欢用git tag打包……

在Firefox里用光大网银

// WIP,光大网银很多javascript代码貌似在ff下就有问题,这里只是说ActiveX的问题

光大网银用了ActiveX,于是看上去很难在别的系统/浏览器下用。

但其实就结果来说,那个ActiveX控件没啥用……

页面上有三个<object>,其中一个啥sign貌似啥都没干,另外俩负责加密密码/提交。

提交登录表单的时候,多数域都是空的。根据观察,控件就填了一个域:Password

为了观察那个控件都调了啥加密函数,找了个很好用的工具,叫WinAPIOverride。粗粗一看调了若干Crypt* API,于是缩小范围到各个Crypt*函数上。分析记录在 http://wiki.henryhu.net/wiki/CEB

最后发现这个控件很匮乏,在用公钥加密了密码之后(公钥在JS里……),它蛋疼的生成了一个随机数加密了一下,之后有解密了一把,最后完全没用…… 而那个Password域,内容其实就是密码加密结果反过来之后base64一把……

分析的时候有个地方很奇怪。看上去CryptEncrypt()的输入每次都一样,但是结果每次不同…… 后来自己写了个程序试试发现的确每次不同…… 再次看见网上说,加密时候会随机pad到block长度,才理解……

接下来嘛,写个Greasemonkey脚本来帮助登录。第一步就是把那几个控件替换成我们的对象。替换完之后,可以登录过第一步了,之后手机短信验证还是不成。看console里有个错说HiddenSubmitArea不存在,于是插入一个进去…… 这货找遍各个地方都没找到,貌似也没啥用。

这样就可以过短信验证了…… 进去之后貌似还是有一些js错误,慢慢来…… 反正可以登录了。

作为库调用跟踪工具,WinAPIOverride还是挺好用的,功能上类似于ltrace,还有调试器的一部分功能,可以在库函数调用前后断下来,观察内存/寄存器等。IEinspector作为分析IE数据包的工具也不错,看上去比HttpFox功能更多…… 只是要收钱。

Greasemonkey代码:

// ==UserScript==
// @name        cebbank
// @namespace   net.henryhu
// @description ceb bank
// @include     https://www.cebbank.com/per/perlogin*
// @include     https://www.cebbank.com/per/prePerlogin.do?_locale=zh_CN
// @version     1
// @grant       none
// ==/UserScript==
 
function reset() {
    console.log('reset');
}
 
function publicKeyBlob(blob) {
    console.log('blob: ' + blob);
}
 
function commit(field) {
    console.log("commit: " + field);
}
 
function submit(formName) {
    console.log('submit: ' + formName);
    form = document.forms[formName];
    form.Password.value = '';
    form.submit();
}
 
function HiddenSubmitArea(foo) {
    console.log('HiddenSubmitArea: ' + foo);
}
 
oldpc = document.getElementById('powercommit');
newpc = document.createElement('div');
newpc.id = 'powercommit';
newpc.reset = reset;
newpc.submit = submit;
 
oldpp = document.getElementById('powerpassword');
newpp = document.createElement('input');
newpp.id = 'powerpassword';
newpp.type = 'password';
newpp.publicKeyBlob = publicKeyBlob;
newpp.commit = commit;
 
counter = document.createElement('input');
counter.value = 1;
counter.id = 'counter';
document.body.appendChild(counter);
 
if (oldpc) {
    oldpc.parentNode.replaceChild(newpc, oldpc);
    console.log("replaced pc");
}
 
if (oldpp) {
    oldpp.parentNode.replaceChild(newpp, oldpp);
    console.log("replaced pp");
}
 
window.HiddenSubmitArea = HiddenSubmitArea;

在FreeBSD的Flash里输入中文

对其他系统用户这大概都不是什么问题,但是在BSD系统上有一堆问题……

环境:FreeBSD 11, 打了个patch所以用的centos 6作为linux_base。

首先是glibc是否支持locale的问题。貌似linux_base-c6没有产生locale数据库,所以要跑build-locale-archive。
之后跑linux的locale应该就不会报错了。

其次看gtk的xim输入法模块是否启用了。找个gtk2-devel的包,从里面可以找到gtk-demo,跑他可以检验。
默认貌似只装了gtk2包,没装immodule…… 找到gtk2-immodules-xim包,把里面的im-xim.so装到/compat/linux/usr/lib/gtk-2.0/2.10.0/immodules里。这还没完,还要更新immodules列表。跑linux的gtk-query-immodules-2.0,把结果写到/compat/linux/etc/gtk-2.0/i386-redhat-linux-gnu/gtk.immodules里。之后开gtk-demo,找个文本框,右键菜单->输入法里应该有XIM了。

这时可能还是无法激活输入法。我写了个小程序检查XIM的情况:

#include <X11/Xlib.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
int main() {
        Display *dpy = XOpenDisplay(NULL);
        if (!dpy) {
                printf("fail to open display\n");
                exit(1);
        }
        if (XSupportsLocale()) {
                printf("Xlib supports current locale\n");
        }
        char *p = XSetLocaleModifiers("");
        printf("current locale modifier: %s\n", p);
        XIM im = XOpenIM(dpy, NULL, NULL, NULL);
        if (!im) {
                printf("fail to open im\n");
                exit(2);
        }
        printf("locale of IM: %s\n", XLocaleOfIM(im));
}

如果没有显示Xlib supports current locale,那linux的libX11不支持现在的locale…… 我发现X11的locale没装,找到libX11-common包,把里面的东西解压到/compat/linux里。之后再跑就没问题了……

这些都搞完之后,gtk-demo就可以输入中文了。重启浏览器,Flash终于也可以了……

在美国搞加拿大签证

Update 2014.11.08:
现在交护照的方法已经不一样了,这里的信息过期了。
现在不分单次多次了,反正全都100刀。

加拿大签证真是容易搞,这次居然给了我个多次进入直到护照有效期的签证……

参考:http://www.shijiebang.com/u5815/blog-4561/

因为去年底加拿大在纽约的Visa Application Center关门了,没法面签,于是我在线搞的。其实挺快的。

在线申请

https://clegc-gckey.gc.ca/j/eng

去这里注册一个账号,然后登陆,填一些基础信息。

然后开始填各种电子表格。包括:

× IMM5257E VISA申请表

基本信息表格,里面UCI是空的。我country填的中国,current country of residence填的美国,日期填的I-20上的日期……

Purpose填的Tourism,Fund我填了5000…… 在我打算访问的人里我填了Nuk…… 最后Validate一下就行了。另存填完的版本。

× IMM5645E 家庭信息

家庭成员信息,名字要中英双语。别的没啥。在线提交貌似不用签名。

× Itinerary, Travel

我写了个简单的文,说我要开车过去找同学玩…… 虽然说我还没有驾照是吧…… 毕竟因为还没确定下来,我还没搞机票,其实交机票行程单也行。

× Purpose of Travel

我交了I-20…… 虽说其实文不对题吧,但是大概也没啥关系,该交的都交了就行了。

× Proof of Means of Financial Support

我交了最近三个月Bank Statement的扫描件。

× Passport or Travel Document

把护照扫描件交了上去,和Travel History一样……

× Digital Photo

随便搞个照片传上去

× Travel History

把护照扫描件交上去,包括护照信息页和每一个签证。

如果有啥这里没有的项目,说明你之前选多了,例如选了有人邀请你之类…… 其实都不用。

另外交签证费:多次入境,150加元…… 如果只要单次可以便宜一半,而且据说返回美国再回来也在单次的允许范围。

交护照

我交在线申请信息是1/31。2/5收到一个消息,说让我去真人交护照。给的参考地址:http://www.cic.gc.ca/submit

交护照的同时要交一个Prepaid Priority Express 信封,否则会用平信寄过来…… 那个信封20刀,在领馆附近的USPS:

https://tools.usps.com/go/POLocatorDetailsAction!input.action?locationTypeQ=po&address=New+York%2C+NY&radius=10&locationType=po&locationID=1379650&locationName=ROCKEFELLER+CENTER&address2=&address1=610+5TH+AVE+STE+CONC1&city=NEW+YORK&state=NY&zip5=10020&zip4=9991&tollFree=800-ASK-USPS%26reg%3B%26nbsp%3B%28800-275-8777%29&fax=&tAddress=&tAddress1Ams=&tAddress2Ams=&tCityAms=&tStateAms=&tZipAms=&tCarrierRouteAms=&latitude=40.75820913600046&longitude=-73.97747646099964&sWithin=10&&&&&&&&&

在Rockfeller center,进了610号之后到地下,右转就到。去自动柜员机,要一个Priority Express的邮票,19.99刀。然后拿一个Priority Express的信封,贴上邮票,再拿一个地址单贴上,目的地写我家,始发地写使馆地址:

Canadian Consulate General in New York

1251 Avenue of the Americas

New York, NY 10020

交护照的地方是个很小的office,也在地下,我第一次走的时候因为觉得看着不像还找了一会…… 敲门进去说我是交护照的,把信封,护照和确认信交了就好了。

具体来说,交护照的地方是在Avenue of the Americas那个Chase楼的地下。从侧面的门进去,在左侧有个通往地下的通道,上面有牌子说加拿大使馆在下面。下去之后走了一段左手侧有个小办公室,就是那个…… 门口贴了一堆啥通知流程之类的……

签证到手

大约2/12护照就寄回来了,签证给到了护照有效期,大概有七年…… 真是随意……

多谢Orange指点……