12
28
2011
11

利用脚本提升 Wine QQ 登录体验

我从某处下载的QQ2010,其它都好,就是登录时焦点在密码框时,QQ就会崩溃。解决办法是使用QQ自带的软键盘输入密码。但在这个「半字母顺序」排列软键盘上找需要的需要实在费事。作为一名 Linuxer,我自然得想办法将其自动化。

很久之前就已经看到这个Xpresser软件,但可惜的是,它在Arch下跑不起来。但我从中学到了简单的图像匹配,再加上自己对 Xtest 的了解,解决方案呼之欲出。

本来是三个月前就打算写篇文章的,因各种原因迟迟未写。现在因为各种原因再次折腾这家伙,还是写出来分享一下吧。使用OpenCV做图像匹配部分我就不写了,有兴趣的自己去看 Xpresser 或者 winterpy 中的代码。

首先,介绍一下依赖。本脚本依赖众多的东西,其中我自己写的部分在 winterpy 里有,主要是 OpenCV 图像匹配,以及之前写过的 Xtest 调用使用 GDK 截图。最终,我利用它们写成了 xauto.py 库,功能还十分欠缺,但自动登录Wine QQ足够了,因为我做这些的主要目的就是这可恶的QQ。

#!/usr/bin/env python3
# vim:fileencoding=utf-8

import os
import sys
from xauto import XAuto, Image

QQNo = 'YourQQNo'
QQPwd = 'YourQQPassword'

def main():
  if os.fork() == 0:
    if os.fork() == 0:
      os.execlp('rwine', 'rwine')
    else:
      sys.exit()
  os.chdir(os.path.split(sys.argv[0])[0])

  rect = (20, 150, 500, 500)
  xa = XAuto()
  w, h = xa.screensize
  target_w, target_h = 500, 300
  w, h = w - target_w, h - target_h
  w, h = w // 2, h // 2
  center = (w, h, target_w, target_w)
  xa.default_rect = center

  xa.find_and_click('ok.png', repeat=10) or sys.exit('click 确定')
  xa.find_and_click('qq.png', repeat=10) or sys.exit('find qq no input')
  xa.wait(1)

  for k in QQNo:
    xa.key(k)

  xa.wait(0.4)
  pwd_pos = xa.find('input_pwd.png')
  xa.click(pwd_pos)
  caps = Image('caps.png')
  xa.wait(0.4)
  for ch in QQPwd:
    xa.find_and_click('%s.png' % ch) or sys.exit(2)
    xa.wait(0.1)
    xa.find_and_moveto(caps)
    xa.wait(0.1)
  xa.moveto(pwd_pos)
  xa.wait(0.4)
  xa.find_and_click('login.png')

if __name__ == '__main__':
  main()

几点说明:

  1. 执行以下命令禁止QQ记住用户信息,这样再次启动时焦点会在输入QQ号的地方而不是会导致崩溃的密码框。如果你使用我给的压缩包的话应该可以跳过。
    rm -rf Users/All\ Users
    mkdir Users/All\ Users
    chmod -w Users/All\ Users
    
  2. 需要 wine 1.3.32 或更低,以及 wine_gecko 1.3 或更低。新版本在调用 IE 的组件进行显示时会崩溃,这包括「消息管理器」、「查看聊天历史」、「聊天窗口」的侧栏等。
  3. 我执行的是自己包装过的具有隐私保护功能的「rwine」程序。不过也不是特别安全,QQ仍能够访问剪贴板、截图等。
  4. 密码当然是明文保存。你觉得有必要折腾的话可以自己修改。
  5. 程序中需要的图片自己截。应该很容易知道应该截哪里。这样也避免了字体不同导致图像匹配失败。
  6. 此版本的 QQ 可以在这里下载:115 网盘

另注:更简洁好用的 TM2009 没有 wine 成功,登录时弹出错误


2014年3月25日更新:TM2009 以及 TM2013 后来均 Wine 成功了,并且在输入密码时不会崩溃。详情见此文

Category: Linux | Tags: python QQ wine 腾讯
12
24
2011
64

危险的 Microsoft Word

在编辑 Word 文档时,记住 Microsoft Word 是危险的会很有用。

因为毕业设计的关系,需要使用 Word 文档。我用的是 Microsoft Word 2007,因为没有理由让我使用更旧的版本,而我也没有更新的版本。这才使用几天,我已经忍不住要来吐槽了。

几天前,寝室断电。于是乎,几百字不翼而飞。Word 有自动保存文档以供恢复,但默认是每十分钟才保存一次。这比我手动保存的频率还低。那次断电,Word 是唯一给我造成损失的软件。是的,我的火狐打开了若干标签页。但是没关系,除了最后几秒打开的标签页,其它时候火狐异常退出再打开时,所有的标签页都还在,只要重新载入就可以了。如果已经在某网页里输入了较多文字的话也没关系,Textarea Cache 会帮我保存它们的。至于自己最常用的 Vim,更是无需担心。Vim 默认每输入 200 个字符,或者停止操作 4 秒就会将修改写入交换文件。所以,我从来没有在 Vim 里在没有误操作的情况下丢失大量文字。

好吧,既然 Word 默认的 10 分钟太久了,那我改短点总行了吧?于是我把它改成了 1 分钟。结果,在我尝试在页脚插入页码的时候,我发现突然卡了一下,右下方出现了绿色的进度条。不过在我注意到它时它已经完成了。因为生疏,所以我又继续弄好了一会儿,然后,绿色的进度条又出现了。我看清楚了,它在保存文档。很慢,看样子是完整地保存了一份。Word 这次不仅仅是卡住了,而且——它崩溃了!哦不,在微软的字典中没有「崩溃」这个词。最多只能说是「异常退出」。当然这个词也不常用。微软最常用的是「程序遇到问题需要关闭」。就是这么一个框跳了出来,问我要不要发送报告。好吧,你发吧。点击「发送错误报告」,Word 继续卡在那里……等了会儿,我不耐烦地点了取消,它还没反应。最后终于反应过来,Word 告诉我有一大堆文档「已经修复」。这个我已经见怪不怪了,打开阅读的文档,我不记得做了任何修改,但 Word 总是喜欢问要不要保存。再看看那篇在自动保存中崩溃的文档,「已经修复」的版本格式已经乱掉了。我还是从自己手动保存的版本继续吧。

用 Vim 久了,以前在 Windows 下养成的随时保存文件的习惯渐渐地消失了。现在,重返 Windows,重返 Word,我得在使用过程中时刻提醒自己,要随时手动保存。自动保存并不可靠,甚至还可能是崩溃发生的根源。撒销什么的也不再可靠,要记得编辑一段时间去资源管理器里选中文档,Ctrl-CCtrl-V下,不然,当自己不小心把排版弄乱而 Word 又撒消不回来时就郁闷了。

2011年12月25日更新:Windows 也一样不可靠,竟然应用更新后置我打开的众多文档和程序于不顾,自动重启,完成后还不恢复打开的应用程序——

Windows 最近下载并安装了一个重要安全更新……此更新要求自动重新启动您的计算机!

Category: Windows | Tags: office windows 微软
12
21
2011
5

Rcode.vim 2.0 发布

Rcode, 即「Run Code」的缩写。Vim 拥有多种脚本语言的接口。有时候需要对文本进行较复杂的处理,但是在单行的命令行里能写的代码功能有限。你可能会立即想到,先把代码写到一个文件里再加载。没错,这就是 Rcode.vim 为你做的。2.0 版本在原来简单的「编写」->「执行」基础上添加了代码保存功能,可供重新载入(并加以修改)。此特性是由易名建议的。

命令和键映射:
:Rcode		启动 Rcode,需要一个参数指明语言,如 vim、
		awk 等。使用 <C-D> 可以查看所有当前被
		支持的语言。会开启一个新的缓冲区,请把你的代
		码写在里边。此命令可以接受一个范围。

:RcLoad {name}	加载之前保存的代码。
		「name」是「{lang}/{filename}」的形式,这和
		保存的参数有些不同,因为脚本需要知道代码的语种。
		此命令可以接受一个范围。

:RcSelect	列出所有已保存的代码,使用数字来选择。

在 Rcode 的缓冲区里:

<C-CR>
:Run		在你启动 Rcode 时的缓冲区上执行代码。
:Save {name}	保存代码以在日后可使用「:RcLoad」命令载入。

别名:
在 Python 中,「v」为「vim」模块,「b」为当前的缓冲区对象。
在 Lua 中,「b」为当前的缓冲区对象。 

设置:
g:Rcode_after	执行代码后的行为。
		0 什么也不做,1 关闭该窗口,2 关闭的同时也不
		要记住代码,不然下次使用「:Rcode」命令时会显
		示此代码。默认值为 1。

g:Rcode_snippet_path	代码保存的路径。
			默认值是 "$HOME/.vim/rcode"。

下载地址

Category: Vim | Tags: vim
12
18
2011
7

在 Arch 上使用 PulseAudio

一直不怎么懂关于音频的配置,所以一直没管这方面,直到遇到小麻烦。我把gnome-volumn-control干掉之后,发现音量无法调到 100% 以上了,某些视频音量太小听不清。这才第一次正视音频配置。

其实也说不上有多么「正视」,因为我只是在 ArchWiki 上找了几条命令执行了下而已。

安装了以下软件包:

  • pulseaudio-alsa, 就一个配置文件,用处不明
  • pamixer-git. 命令行调节音量用的,Awesome 音量 widget 改用这个了
  • pavucontrol, 图形界面的音量调节工具。更新后的 Awesome 音量 widget 上点右键运行它,可以针对不同的程序进行调节

另外,在 mplayer 的配置文件中加了ao=pulse这行。

就这些了。

Category: Linux | Tags: Arch linux awesome 音频
12
5
2011
13

Awesome 调节音量不再依赖 GNOME

之前一直在用 gnome-sound-applet 来调节音量。今天终于脱离了它。

GNOME 越来越臃肿了。今天系统出了点小问题,查看日志时再次看到 dbus 报怨 NetworkManager 没有运行的错误。我是直接用的 ArchLinux 的network服务连网的,根本不需要 NetworkManager 掺和,可是自己要用 Empathy,而它奇迹般地依赖 NetworkManager。。。虽然试了下强制卸载,最后只成功pacman -Rdd几个其它的包,没能在保证 Empathy 能用的前提下干掉 NetworkManager,心中多有不甘。于是开始打 gnome-sound-applet 的主意。

gnome-sound-applet 这东西是 gnome-control-center 的一部分,其依赖了 15M 左右的奇怪 GNOME 组件。这个 applet 也很鸡肋,本来是显示和调节音量用的,结果黑黑的图标在我的灰色 Awesome 面板上并不容易找到,花了良久才习惯。另外就是,该图标本身不提供任何信息,查看音量时需要把鼠标悬停过去,心中多有不爽。好在今天这些问题一并解决了。

参考来源是 Awesome Wiki 的这个页面,不过这里的代码太老了,不能用,自己参照rc.lua的其它部分以及 wiki 和 reference 修改之后才能用。最终的效果是这样子的:

Awesome widgets 截图

你应该很容易能猜到最右边的就是音量控制了,因为它前边有个八分音符符号“𝅘𝅥𝅮”。鼠标操作很简单:单击切换静音,上下滚动调节音量。静音时百分号会被红色的“M”取代。

贴代码:

-- {{{2 Volume Control
volume_cardid  = 0
volume_channel = "Master"
function volume (mode, widget)
  if mode == "update" then
    local fd = io.popen("amixer -c " .. volume_cardid .. " -- sget " .. volume_channel)
    local status = fd:read("*all")
    fd:close()

    local volume = string.match(status, "(%d?%d?%d)%%")
    volume = string.format("% 3d", volume)

    status = string.match(status, "%[(o[^%]]*)%]")

    if string.find(status, "on", 1, true) then
      volume = '𝅘𝅥𝅮' .. volume .. "%"
    else
      volume = '𝅘𝅥𝅮' .. volume .. '<span color="red">M</span>'
    end
    widget.text = volume
  elseif mode == "up" then
    io.popen("amixer -q -c " .. volume_cardid .. " sset " .. volume_channel .. " 5%+"):read("*all")
    volume("update", widget)
  elseif mode == "down" then
    io.popen("amixer -q -c " .. volume_cardid .. " sset " .. volume_channel .. " 5%-"):read("*all")
    volume("update", widget)
  else
    io.popen("amixer -c " .. volume_cardid .. " sset " .. volume_channel .. " toggle"):read("*all")
    volume("update", widget)
  end
end
volume_clock = timer({ timeout = 10 })
volume_clock:add_signal("timeout", function () volume("update", tb_volume) end)
volume_clock:start()

tb_volume = widget({ type = "textbox", name = "tb_volume", align = "right" })
tb_volume.width = 35
tb_volume:buttons(awful.util.table.join(
  awful.button({ }, 4, function () volume("up", tb_volume) end),
  awful.button({ }, 5, function () volume("down", tb_volume) end),
  awful.button({ }, 1, function () volume("mute", tb_volume) end)
))
volume("update", tb_volume)

记得把 tb_volume 加到 wibox 里去。

这里是我的整个 Awesome 配置。

2013年3月11日更新:Awesome 3.5 版本语法变化较大,请到我的 github 上查看相关代码。

Category: Linux | Tags: arch awesome gnome Lua linux
11
28
2011
7

弄了个支持 readline 的 MongoDB shell

不知道怎么搞的,新版 MongoDB 自带的 mongo shell 现在不支持 readline,而且使用一个极简到工作不正常的 linenoise。编译时加上 readline 也没用。虽然内建了简单的历史记录和补全,可是历史记录不能搜索,补全只能像 Vim 命令行默认的那样一个一个切换不能像 bash/zsh 那样全部列出来。这些还不是最令人郁闷的。最让我受不了的问题和十年前的 DOS 版 WPS 里遇到的差不多——当年的 WPS 里删汉字一次只删一半,现在的 mongo shell 里删汉字一次只删三分之一!而且光标定位是错的,按字节算的!

于是乎拿 Python 写了一个 shell。不愧是 Python,内置的东西真不错,不到100行就写好了。不过用到了自己另外的库函数,另外用到了自己的 colorless 程序来高亮显示查询结果。如果不想要 pygments 这个依赖的话,可以用 less 程序代替。以下贴个无高亮版的,高亮版的见 github

#!/usr/bin/env python3
# vim:fileencoding=utf-8

import sys
import os
from pprint import pprint
import subprocess

from pymongo import Connection
import pymongo.cursor

# 这个模块位于 github 上的 winterpy 仓库的 pylib/cli.py
from cli import repl

import locale
locale.setlocale(locale.LC_ALL, '')
del locale

host = 'localhost'
port = 27017
db = 'test'

def displayfunc(value):
  if isinstance(value, pymongo.cursor.Cursor):
    p = subprocess.Popen(['less', '-RFX'], stdin=subprocess.PIPE,
                        universal_newlines=True)
    pprint(list(value), stream=p.stdin)
    p.stdin.close()
    p.wait()
  else:
    pprint(value)

def main():
  global db
  conn = Connection(host=host, port=port)
  db = conn[db]

  v = globals().copy()
  v.update(locals())
  del v['repl'], v['argv'], v['main'], v['v'], v['host'], v['port']
  del v['displayfunc'], v['subprocess']
  del v['__name__'], v['__cached__'], v['__doc__'], v['__file__'], v['__package__']
  sys.displayhook = displayfunc

  repl(
    v, os.path.expanduser('~/.mongo_history'),
    banner = 'Python MongoDB console',
  )

if __name__ == '__main__':
  argv = sys.argv
  if len(argv) == 2:
    if '/' in argv[1]:
      host, db = argv[1].split('/', 1)
    if ':' in host:
      host, port = host.split(':', 1)
  elif len(argv) == 1:
    pass
  else:
    sys.exit('argument error')

  main()
Category: python | Tags: python MongoDB linenoise readline
11
26
2011
8

给博客加入 Google +1 按钮

本来我是懒得去做这种东西的,可鉴于以下几个原因,还是弄了一个。

  • Mike 也 +1 了
  • 代码很简单
  • 方便分享到 Google Plus
  • 反正从国内访问本博客也不容易,就不在乎这个 +1 按钮很可能出不来了

代码如下,真的很简单:

<script type="text/javascript" src="https://apis.google.com/js/plusone.js">{lang: 'zh-CN'}</script>
<g:plusone></g:plusone>

我把它加到了每篇文章的末尾,因为我不认为没看完文章的读者会需要用到它。看不到按钮的读者请自行解决对 Google HTTPS 的访问问题。

Category: 未分类 | Tags: Google
11
9
2011
14

在 Arch 上启用 NTP 服务对时

一日即将按算好的时间外出。将系统挂起,出门时检查下手机,却郁闷地发现电脑时间又慢了!十几分钟啊。。。。

我的手机是和移动运营商的网络时间同步的,因此不出事故它是可靠的。看来电脑的时钟也应该同步下了,不然过段时间要手动调下。

毫不犹豫地在ArchWiki里搜索NTP,按wiki进行操作。这wiki写了那么长,其实只要对时的话操作很简单。

  1. sudo pacman -S ntp安装
  2. sudo rc.d start ntpd启动 daemon
  3. vim一下/etc/rc.conf,加入开机启动项中,同时把hwclock干掉

就这么三步。至于同步的时间服务器,默认的pool.ntp.org就挺好的。ntpd 启动后系统时间并没有马上改变,而是过了几分钟才在我不注意的时候悄悄同步准确了。

Category: Linux | Tags: linux arch ntp
10
31
2011
16

在 Linux 下交叉编译带 Python 3 支持的 gvim.exe

今天再一次在 yaourt 的输出中瞥见 mingw 这几个字符,好奇地看了下说明:A C and C++ cross-compilers for building Windows executables on Linux。这个不就是传说中的交叉编译器么?

试试看。以前自己在虚拟机里为 Windows 编译过很多次的 vim,要是能弄到真机下来编译效率应该会高很多。(不,我不是说虚拟机的性能差,而是 Windows 下跑 mingw 这种一堆进程的东西效率差。)

说干就干,几十 M 的 mingw-gcc 及其依赖下好,git archive all|tar x -C ~tmp/vim弄份崭新的 vim 源码,把以前在 win 下用的Make_ming.mak拷过来改改,设置CROSS=yes什么的,然后开始编译!然后很快就出错了,找不到编译器i586-pc-mingw32msvc-gcc。唔,我确实没有那个东东,只有i486-mingw-gcc,去把CROSS_COMPILE这个变量改了就好。然后再 make。这一次的结局是——找不到 Python/Ruby/Lua 的头文件、找不到它们中的符号……好吧,你这交叉编译器当然找不到它们,先注释掉好了。然后重新编译,很顺利地出来个 gvim.exe 了~拿到 Windows 虚拟机里跑一下,一切正常~

好开心,第一次玩交叉编译就成功了。不过还有些小遗憾:没有那些外部脚本语言的支持。这可怎么办呢?我上哪儿找用于交叉编译的库呢?光想是没有用的,还是得尝试。用 Linux 版的库肯定不行,那就试试 Windows 版的。先拿 Python 3 支持测试。把 Windows 下安装的 Python 3 文件夹复制过来,修改下路径,再 make。很正常地,我的第一次尝试总是不成功,好在也不是大问题:Make_ming.mak里写的 include 目录不对:

ifeq ($(CROSS),no)
PYTHON3INC=-I $(PYTHON3)/include
else
PYTHON3INC=-I $(PYTHON3)/win32inc
endif

看看自己的 Python 3 目录,这里的win32inc应该是include。改改就好了 ;-)

嗯,顺利成功了!接下来,把 Windows 版的 Ruby 和 Lua 也弄过来就不用再跑到虚拟机里去编译 Windows 版的 Vim 了!嗯,NSIS 也有 Linux 版,虽然是在 AUR 里。

最后,编译好的 gvim 还是在这里

Category: Vim | Tags: vim windows 交叉编译 编译 linux
10
23
2011
3

使用 fontconfig 进行字体查询

Vayn想知道如何判断一个字体是否支持中文,我也对字体的种种特性好奇,于是我再一次淹没在文档之中。先是翻了半天Pango的文档,各种字体相关的函数,还找到个pango_has_char函数。不过我没能弄明白怎么它需要的参数类型PangoFcFont怎么弄。后来查到这个函数需要底层支持,于是我直接找到 fontconfig 去了。

fontconfig 的文档不怎么样,虽然后来发现它提供了manpages、PDF、HTML、TXT等格式,但我依旧没能从文档中弄明白如何得到一个字体的信息。看了 fc-query 的源代码才知道,原来FcPattern既用来作输入,也用来作输出。查询字体时它是查询条件,而返回时它就是字体信息。

/* ===================================================================== *
 *  判断某个字符是否存在于指定的字体(文件)中
 * ===================================================================== */
#include<stdio.h>
#include<string.h>
#include<fontconfig/fontconfig.h>
/* --------------------------------------------------------------------- */
int main(int argc, char **argv){
  int ret = 0;
  FcChar8* file = (FcChar8*)"/home/lilydjwg/.fonts/迷你简启体.ttf";
  FcPattern* pat;
  FcCharSet* cs;
  FcChar32 ch;
  int count;

  FcBlanks* blanks = FcConfigGetBlanks(NULL);
  pat = FcFreeTypeQuery((FcChar8 *)file, 0, blanks, &count);

  if(FcPatternGetCharSet(pat, FC_CHARSET, 0, &cs) != FcResultMatch){
    fprintf(stderr, "no match\n");
    ret = -1;
    goto cleanup;
  }

  FcUtf8ToUcs4((FcChar8*)"简", &ch, 3);
  if(FcCharSetHasChar(cs, ch)){
    puts("Yes");
  }else{
    puts("No");
  }

cleanup:
  FcPatternDestroy(pat);
  return ret;
}
/* ===================================================================== *
 * vim modeline                                                          *
 * vim:se fdm=expr foldexpr=getline(v\:lnum)=~'^\\S.*{'?'>1'\:1:         *
 * ===================================================================== */
/* ===================================================================== *
 *  判断某个字符是否存在于指定的字体(条件匹配)中
 * ===================================================================== */
#include<stdio.h>
#include<fontconfig/fontconfig.h>
/* --------------------------------------------------------------------- */
int main(int argc, char **argv){
  FcFontSet* fs = NULL;
  FcPattern* pat = NULL;
  FcObjectSet* os = NULL;

  FcChar8* strpat = (FcChar8*)":lang=zh";
  pat = FcNameParse(strpat);
  os = FcObjectSetBuild(FC_FAMILY, FC_CHARSET, FC_FILE, (char *)0);
  fs = FcFontList(0, pat, os);
  if(os)
    FcObjectSetDestroy(os);
  os = NULL;

  FcPatternDestroy(pat);
  pat = NULL;

  if(!fs || fs->nfont <= 0)
    goto nofont;

  FcChar8 *family;
  FcChar8 *file;
  FcCharSet* cs;
  FcChar32 ch;
  FcUtf8ToUcs4((FcChar8*)"这", &ch, 3);
  int i;
  for(i=0; i<fs->nfont; i++){
    if(FcPatternGetCharSet(fs->fonts[i], FC_CHARSET, 0, &cs) != FcResultMatch){
      fprintf(stderr, "no match\n");
      FcPatternPrint(fs->fonts[i]);
      goto nofont;
    }
    if(FcPatternGetString(fs->fonts[i], FC_FAMILY, 1, &family) != FcResultMatch)
      if(FcPatternGetString(fs->fonts[i], FC_FAMILY, 0, &family) != FcResultMatch)
	goto nofont;
    printf("[%d] %s ", i, (char *)family);
    if(FcPatternGetString(fs->fonts[i], FC_FILE, 0, &file) != FcResultMatch)
      goto nofont;
    printf("(%s): ", (char *)file);
    if(FcCharSetHasChar(cs, ch)){
      puts("Yes");
    }else{
      puts("No");
    }
  }

  FcFontSetDestroy(fs);

  return 0;

nofont:
  return 1;
}
/* ===================================================================== */
Category: Linux | Tags: fontconfig C代码

| Theme: Aeros 2.0 by TheBuckmaker.com