分类 赛博艺术 下的文章

只是想做一个看起来很忧郁的小物件,就像《深圳I/O》一样忧郁,于是拓展到了电子工程师的领域(不是)。年前下单买了各种部件,年后才收到,一看发货地,“深圳”。并不是特别艰深的东西,所以本文不会给出全部代码细节,只求读者心领神会。

工程目标很简单,只要联网显示一些不特定的文字即可,所以一共只买了三样东西:ESP8266 + SSD1306 + DHT11。单纯为了额外的趣味性加了个 DHT11 来获取温度和湿度。

我实在不喜欢写 C 或 C艹,也不想学新的,所以往 ESP8266 (NodeMCU) 里面刷了 MicroPython 固件。实际使用 MicroPython 的时候发现还是和正常 Python3 不一样,需要小心功能阉割,尤其是一些库。

ESP8266 支持 WiFi 连接,可以在代码里写好,配置自动联网。但我不想把网络配置写死,所以用了 WiFiManager 来管理网络。如果当前无可用网络配置,它会自动开启热点,在 192.168.4.1 提供一个网页管理界面,我们可以增加新的网络配置。一旦连上网络,新增的配置会写入 flash 永久保存,今后无需手动操作即可连接。当然这个程序现在似乎没人维护了,有个 bug 需要特别注意一下。

至于 SSD1306,我最喜欢这种可爱的小小屏幕了,尤其喜欢把 128*64 的空间利用到极致,我要用最小的 8*8 点阵字体填满它!找这种字体费了些工夫,好在上古时代确实是有人用过的。但是 MicroPython 对 OLED 屏幕的驱动支持还是很弱,ESP8266 的空间和性能也不允许直接使用完整的中文字体。16*16 大小且限制在 GB2312 字符集的点阵字库网上似乎容易找到,但是我还要日文、扩展拉丁字母,不然根本配不上我!所以我最后选择了让云端性能更强的服务器 Python3 + CGI 一下,远程处理文字显示数据。只须提交文字,然后用 Pillow 模块生成图片返回 .pbm 文件即可。这种文件格式非常有趣,前两行是格式说明,可以用两次 .readline() 丢掉,之后 .read() 一次读完即可,后面的二进制数据直接就是逐行记录的点阵!转换成 bytearray 后直接又是 FrameBuffer 的数据格式,实在太便利了!(囧)当然由于 OLED 的本质,还需反色一下才能正确显示,这个也简单,逐字节 ^= 0b11111111 就可以了。

最后决定具体要显示什么。用了免费的新闻 API,和其他一些奇怪的东西,这里就不赘述了。

那么,最后效果是怎样的呢?请看下图:

ssd1306.jpg

真的忧郁。

经过简单的调试,本站现在支持根据需要显示某种字体。我选用了UnifrakturMaguntia并嵌入网页。这款字体是自由软件,请放心使用。

以下是一段测试:

Die Eltern lagen ſchon und ſchliefen, die Wanduhr ſchlug ihren einförmigen Takt, vor den klappernden Fenſtern ſauſte der Wind; abwechſelnd wurde die Stube hell von dem Schimmer des Mondes. Der Jüngling lag unruhig auf ſeinem Lager, und gedachte des Fremden und ſeiner Erzählungen. Nicht die Schätze ſind es, die ein ſo unausſprechliches Verlangen in mir geweckt haben, ſagte er zu ſich ſelbſt; fern ab liegt mir alle Habſucht: aber die blaue Blume ſehn' ich mich zu erblicken. Sie liegt mir unaufhörlich im Sinn, und ich kann nichts anders dichten und denken. So ist mir noch nie zumute geweſen: es iſt, als hätt' ich vorhin geträumt, oder ich wäre in eine andere Welt hinübergeſchlummert; denn in der Welt, in der ich ſonſt lebte, wer hätte da ſich um Blumen bekümmert, und gar von einer ſo ſeltſamen Leidenſchaft für eine Blume hab' ich damals nie gehört. …

此外,为方便输入ſ,我更新了Windows可用的德语键盘布局,在Github可以获取。我将其定位在AltGr+S,没有记忆负担。

你是否对人生感到困惑?你是否有问题无处解答?你是否相信冥冥之中有天命?(我编不下去了。)

请访问 你的答案 寻求答案吧!

运作原理受到了某本实体书的启发。不过我重新编写了答案,经过一段时间的内测受到广泛好评。内测版本基于 Python3 + Qt,使用起来毕竟不太方便,故制作利于发布的网页版。此外如果你使用大屏幕设备访问本站,是否发现右侧边栏有所变化?在此正是相同的技术得以发挥作用!

注:本服务不提供任何担保,对使用本服务造成的一切后果本站不负任何责任。

由于微信公众号机能限制,新建一个专门的赛博艺术分类是本站网页版用户特别的福利。之前存在的一些作品可能也会以这种方式添加进来,这或许比在独立页面上建立超链接列表合理得多。

本次更新缘于瞬间热情低价入手 RPG Maker MV 后,急速完成迷惑游戏一本。未来更新并不保证,但也不排除以同名创作严肃作品的可能。

游戏发布在 Github 上,借助环境之便可以在浏览器上运行。妙处在于,版本管理系统可以记录每个阶段的作品面貌,可谓是只有在新时代条件下才成为可能的文学实践。

游戏地址:https://inkarnation.eleutheria.tech/
国内镜像(同步可能不及时):https://fluviusmagnus.gitee.io/inkarnation-backup/

项目地址:https://github.com/fluviusmagnus/Inkarnation

如果发现加载有问题,请检查网络或考虑更换浏览器。

GoldenDict 在 Linux 上的屏幕取词或许是利用了 X 第二剪贴板的特性,所以当用户选择文本后可以自动在附近弹出一个小按钮,点击后即可查词。而 Windows 上的取词一直不太稳定,唯一稳定的方法是利用剪贴板激活全局热键 Ctrl + C + C,而这对于正在使用剪贴板的情况非常不友好。本次努力是试图利用 AutoHotkey 尽量再现 Linux 上的体验。

#NoEnv  ; Recommended for performance and compatibility with future AutoHotkey releases.
; #Warn  ; Enable warnings to assist with detecting common errors.

; Clip() - Send and Retrieve Text Using the Clipboard
; by berban - updated February 18, 2019
; https://www.autohotkey.com/boards/viewtopic.php?f=6&t=62156
Clip(Text="", Reselect="")
{
    Static BackUpClip, Stored, LastClip
    If (A_ThisLabel = A_ThisFunc) {
        If (Clipboard == LastClip)
            Clipboard := BackUpClip
        BackUpClip := LastClip := Stored := ""
    } Else {
        If !Stored {
            Stored := True
            BackUpClip := ClipboardAll ; ClipboardAll must be on its own line
        } Else
            SetTimer, %A_ThisFunc%, Off
        LongCopy := A_TickCount, Clipboard := "", LongCopy -= A_TickCount ; LongCopy gauges the amount of time it takes to empty the clipboard which can predict how long the subsequent clipwait will need
        If (Text = "") {
            SendInput, ^c
            ClipWait, LongCopy ? 0.6 : 0.2, True
        } Else {
            Clipboard := LastClip := Text
            ClipWait, 10
            SendInput, ^v
        }
        SetTimer, %A_ThisFunc%, -700
        Sleep 20 ; Short sleep in case Clip() is followed by more keystrokes such as {Enter}
        If (Text = "")
            Return LastClip := Clipboard
        Else If ReSelect and ((ReSelect = True) or (StrLen(Text) < 3000))
            SendInput, % "{Shift Down}{Left " StrLen(StrReplace(Text, "`r")) "}{Shift Up}"
    }
    Return
    Clip:
    Return Clip()
}

SendMode Input  ; Recommended for new scripts due to its superior speed and reliability.
SetWorkingDir %A_ScriptDir%  ; Ensures a consistent starting directory.

CoordMode, mouse, Screen
Gui, New, +AlwaysOnTop -Resize -MaximizeBox -MinimizeBox +MinSize -Caption, Dict
Gui, Add, Button, cBlue gSearch X0 Y0, Search
Gui, Margin, 0, 0
Gui, Show, NA AutoSize, movinggui
settimer, WatchCursor, 1000
return

WatchCursor:
MouseGetPos, oX, oY
WinMove, movinggui, , oX +20, oY + 20
return


OnMessage(0x0201, "WM_LBUTTONDOWN")

WM_LBUTTONDOWN()
{
  If (A_Gui)
    PostMessage, 0xA1, 2
}

Search:
Send, !{Tab}
Sleep, 300
text := Clip()
run "C:\Program Files (x86)\GoldenDict\GoldenDict.exe"  %text%
return

不得不承认 AHK 的脚本语言真的非常反人类。我就随便写写了。

不足之处在于,一个按钮会始终跟随光标,怎样根据需要显示我不会。此外,为了让用户能点击到,设置了一秒的运动延迟。GoldenDict 程序路径以及按钮位置等参数可以根据需要在脚本中修改。

GoldenDict 的弹出窗口可以用命令行调用,这个功能真是隐蔽,此前闻所未闻。

脚本参考了:

在此感谢。