用Java为Nintendo DS编写

图片

引言


一切始于我无意间找到了Nintendo DS的自制程序列表(由用户的努力开发的程序,这些设备不是为运行用户软件而设计的),而我看到了一个非常有趣的一行,即:“ Pstros NDS-MIDP实现运行在为NDS编译的CLDC Java机器上。

作为Java和Nintendo DS的忠实拥护者,我决定弄清楚这是哪种野兽,并在可能的情况下尝试为该JVM编写应用程序。 那些有兴趣要猫的人。

伪装


从网站上下载了珍贵的档案后,我开始对其进行研究。 阅读自述文件后,事实证明Pstros NDS是Nintendo DS的KVM端口(由Sun Microsystems开发的Java虚拟机)。 如下Internet 文章第1条第2条 )所述,此Java机器是为RAM数量有限的小型设备设计的,属于Java平台的一个子集-J2ME。

J2ME体系结构


J2ME具有模块化架构,其中配置和概要文件是核心元素。

配置是一种规范,描述了用于特定移动设备系列的可用开发工具(一组Java语言功能,虚拟机功能和特性,最低支持的库)。

该配置文件扩展并补充了特定移动设备的配置功能。 它可以使用图形显示,通讯功能,特定的外围设备(在我们的情况下,这是触摸屏)。

J2ME体系结构图如下所示:

图片

启动自制程序


您不能只在控制台上运行Nintendo未经认证的软件。 为了解决这个问题,创建了特殊的闪存盒(实际上,它们很可能是为了发行盗版游戏而创建的,而自制软件是副产品,但故事并非如此)。

AliExpress上有许多价格实惠的闪存选项。 我自己订购了R4i Dual Core。 使用它非常简单:只需将特殊存档解压缩到microSD根目录中,然后使用jvm格式的Java机器在那里上传文件,将闪存盒插入控制台即可使用。

图片

KVM的首次发布


Pstros NDS存档中有几个Java程序示例。 要运行这些程序,需要将它们放在microSD闪存盒中的任何位置。 启动kvm.nds之后,您将能够在文件系统上选择文件:

图片

选择文件Hello.class之后,我们将看到以下内容:
图片

其他一些示例应用程序:

图片

图片

仿真器


据我所知,将Nintendo DS直接连接到计算机是不可能的。 持续将microSD从计算机粘贴到设备上,然后再返回查看结果,时间太长。 因此,对于应用程序的测试启动,我们将使用流行的DeSmuME仿真器。

在启动DeSmuME的自制程序时有一些功能。 据我了解的问题,这源于在闪存盒上使用文件系统的问题。

为了使自制应用程序与文件系统交互,编写了libfat库。 但是,任天堂DS的闪存盒数量很多,并且它们都使用特定的文件读/写命令。 libfat库无法识别这些命令,并向自制程序发送错误消息。 为了避免这种情况,发明了一种称为DLDI(动态链接的设备接口)的技术。 它充当自制程序和闪存卡之间的一层,将特定的读/写命令转换为libfat库可以理解的命令。

尝试启动DeSmuME kvm.nds时,出现以下错误:

图片

模拟器的FAQ指示将自动应用DLDI修补程序,但是要正确访问文件,必须在GBA插槽中指定MPCF闪存卡设备,如下图所示:

图片

之后,JVM将正常启动。

搭建开发环境


使用jvm研究存档文件时,我注意到了_rebuild.bat文件。 其内容如下:

内容_rebuild.bat
SET WTKDIR=c:/wtk22 SET CP=%WTKDIR%/lib/cldcapi10.jar;%WTKDIR%/lib/midpapi20.jar;./classes.zip del .\output\*.* /Q "c:/program files/java/jdk1.5.0_06/bin/javac.exe" -source 1.3 -target 1.1 -bootclasspath %CP% ./src/*.java %WTKDIR%/bin/preverify -classpath %CP% ./src del .\src\*.class /Q copy output\*.* .\ 


由此可见,如何为jvm构建应用程序以及我们需要哪种环境。 在oracle网站上,归档文件包含我们需要的wtk和jdk版本。 根据bat文件中指定的路径安装它们(或编辑bat文件中的路径),然后就可以开始开发了。

应用开发


根据我的工作性质,我与库一起工作很多,以创建Swing GUI。 我喜欢这个库,因此举个例子,我决定编写自己的实现。 我决定在“黑匣子”的基础上进行开发,即 知道它应该在外面看起来如何,不要看它在内部如何布置。 首先,由于我计划的库的功能将大大减少(因为我出于娱乐目的而开发它),并且可能对我来说根本不需要Swing中使用的许多解决方案。 其次,提出自己的实现要有趣得多。

从构建脚本中可以看到,您将不得不在Java 1.1下进行开发。

至于要求,首先,我希望库用户支持调用对话框表单的典型Swing代码:

 MyDialogForm myDialogForm = new MyDialogForm(this, true); myDialogForm.setVisible(true); if (myDialogForm.getAnsewer()) { // TODO - do something here } 

即 在这种情况下,将显示对话框窗体,并且在关闭之前,执行不会超出setVisible(true)。 同时,对于被调用表单上的其他组件,应继续处理其用户操作。

下图显示了库操作方案的第一个版本:

图片

从图中可以看到,每个用户操作都是在单独的线程中执行的。 通过此实现,可以满足使用对话框表单的要求,但是,存在一个问题,即处理程序中的用户可以同时使用来自两个线程的相同数据(例如,通过快速单击两个按钮)。 这给保护用户访问此类数据的需求带来了额外的不便。

我们假设所有形式都是交互式的,即 当显示一种形式时,不可能与其他形式一起使用。 在这种情况下,这是一个适当的假设,因为Nintendo DS屏幕不大,并且一次显示多个表格非常不便。

在这种情况下,库操作方案采用以下形式:

图片

即 每个表单都创建自己的处理用户应用程序动作的流程。 如果由于处理动作而调用了新表单,则调用该表单的线程将等待该表单关闭,此时将创建一个用于处理用户动作的新线程。

下面显示了使用库的示例代码:

工作实例
 JNDSComponentsForm jNDSComponentsForm = new JNDSComponentsForm(); jNDSComponentsForm.setTitle("Main form"); final JNDSLabel jndsLabel = new JNDSLabel("Simple label", 20, 30); jNDSComponentsForm.addComponent(jndsLabel); JNDSTextField jndsTextField = new JNDSTextField("Hello world", 20, 58, 150); jNDSComponentsForm.addComponent(jndsTextField); JNDSButton jndsButtonDialogForm = new JNDSButton("Show dialog form", 20, 90); JNDSAction jndsActionImplDialogForm = new JNDSAction() { public void action() { final JNDSDialogForm jndsDialogForm = new JNDSDialogForm(); jndsDialogForm.setTitle("Dialog form"); JNDSButton jndsButtonClose = new JNDSButton("Close", 10, 130); jndsButtonClose.setClickAction(new JNDSAction() { public void action() { jndsDialogForm.setVisible(false); } }); jndsDialogForm.addComponent(jndsButtonClose); JNDSLabel jndsLabelDialogForm = new JNDSLabel("This is Dialog Form!", 70, 80); jndsDialogForm.addComponent(jndsLabelDialogForm); jndsDialogForm.setVisible(true); } }; jndsButtonDialogForm.setClickAction(jndsActionImplDialogForm); jNDSComponentsForm.addComponent(jndsButtonDialogForm); jNDSComponentsForm.setVisible(true); JNDSWindowsManager.instance().run(); 


与Swing中一样,首先描述表单的布局和用户操作处理程序,然后将控制权转移到库中,该库将初始化上下文并在触摸屏上渲染和处理单击。

我遇到的另一个问题是键盘。 不幸的是,我没有找到一种方法来调用操作系统的现成屏幕键盘。 因此,我不得不自己做,大大简化了它的实现。 她的工作结果如下:

图片

目前,作为组件,我仅实现了Label,TextField和Button。 例如,我认为足够; 上述表单的外观如图所示:

图片

完整的源代码可以在这里找到。

在真实设备上启动


我们将编译后获得的* .class文件复制到闪存盒中,运行kvm.nds并在其中选择ExampleJNDSWindowsManager.class。

以下视频介绍了应用程序的结果:


结论


最后,我要感谢Nintendo DS的创建者,Nintendo DS的JVM端口的开发人员,闪存盒的创建者有机会开发自己喜欢的硬件,以及我的妻子为拍摄视频和编辑本文提供的帮助。

谢谢大家的关注!

Source: https://habr.com/ru/post/zh-CN468971/


All Articles