Windows 10/11 直接重启进入 Setup的方法

根据【参考1】,评论区有人提到,以管理员权限运行cmd窗口下输入如下命令即可立刻重启进入 Setup 界面:

shutdown /r /fw /t 0

此外还可以用下面的命令让系统进入 Boot Option 界面

shutdown /r /o /t 0

结合【参考2】编写直接申请权限然后执行操作的批处理

参考:

1.https://zhuanlan.zhihu.com/p/606258549

2.https://www.lab-z.com/batadm/

香港保险投诉局案例分析1

最近听说香港有一个“香港保险投诉局(Insurance Complaints Bureau)”,它一家成立于2018年1月16日,前身是香港保险投诉索偿局,是一个独立的、非营利性的保险纠纷调解机构。该机构旨在为保险消费者提供便捷、高效的纠纷解决服务,维护消费者权益,促进保险市场的公平和诚信。

也就是说当投保人申请理赔时遇到拒赔时,且认为理赔结果不合理时,无需先走司法程序,可直接向保险投诉局投诉,他们接到投诉后将以裁决的方式处理。【参考1】

好奇之下,去看看他们的案例【参考2】,第二页:

何谓「表面证据不成立」?

陈先生计划于2021年7月前往上海,并向保险公司投购旅游保险,而保险公司网页上闪烁的宣传字句「隔离现金津贴」吸引了他的注意。
根据中国对2019冠状病毒病疫情实施的检疫政策,陈先生于上海的一家酒店接受了 14 天的集中强制检疫,酒店费用接近12,000人民币。回港后,他向保险公司申索于隔离期间的酒店费用,但他的索偿遭保险公司拒绝。
有关保单的「强制隔离现金津贴」条款订明:「如受保人因疑似感染或确诊患上传染病而于旅程期间或于返回常住地方后七日内被强制隔离,保险公司将就每个完整天数支付现金津贴500港元……」
陈先生的个案被定为表面证据不成立,原因是:
1) 他被强制隔离的原因并非因为疑似感染或确诊患上传染病;及
2) 保险的原则仅就不可预见或预料的事件向个人或实体提供保障。由于内地当时的政策要求
所有到上海的入境旅客必须隔离至少 14 天,因此相关隔离而导致的酒店费用属预期和可
以预见,不符合保险的承保原则。

这就是为什么语文要做阅读理解吧?话说保险条款还真是阅读理解的好材料。

三十多年前,我老家(大庆市)流传着一个故事。本地人习惯将罐车称作“大罐”。

然后有“狡猾”的外地人过来和本地人签合同,内容是以几十万元的价格出售“大罐”给本地。交付的时候,真的是大铁罐,但是合同如此,最终官司打不赢白白让对方占了便宜。

参考:

1.https://baijiahao.baidu.com/s?id=1820155891286124609&wfr=spider&for=pc

2.https://www.icb.org.hk/gb/doc/ICB-Connect-Issue-1.pdf

Step to UEFI (297)编写一个 UEFI Shell Command 的框架

本文根据 https://github.com/apop2/GopRotate 的代码编写,这个在之前的【参考1】和【参考2】中有介绍过。

本文介绍了如何编写一个 UEFI Shell Command 的方法,然后给出了一个基本的框架,有需要的朋友可以方便的扩展定制自己所需的 UEFI Shell。代码在 edk2 202411 下实验成功。

以WinHost 模拟器为例,介绍例子的测试方法:

1.解压到 \ShellPkg\Library 下面

2.修改 \EmulatorPkg\EmulatorPkg.dsc文件

BcfgCommandLib|ShellPkg/Library/UefiShellBcfgCommandLib/UefiShellBcfgCommandLib.inf
      IoLib|MdePkg/Library/BaseIoLibIntrinsic/BaseIoLibIntrinsic.inf
##LABZDEBUG_Start
	  NULL|ShellPkg/Library/MyShellCommandLib/MyShellCommandLib.inf
##LABZDEBUG_End	

    <PcdsFixedAtBuild>
      gEfiMdePkgTokenSpaceGuid.PcdDebugPropertyMask|0xFF
      gEfiShellPkgTokenSpaceGuid.PcdShellLibAutoInitialize|FALSE
      gEfiMdePkgTokenSpaceGuid.PcdUefiLibMaxPrintBufferSize|8000

3.重新编译,使用 build -a X64 即可

运行 WinHost测试如下:

这里定了一个 mycmd 命令,然后可以接受一个参数。MyCommand.c 中的MyShellCommand() 函数负责实际执行 ShellPkg\Library\MyShellCommandLib\MyShellCommandLib.c 中的MyShellCommandLibConstructor() 函数负责向 Shell 注册 mycmd 命令,同时注册一个帮助文本,通过 STR_GET_MYCMD_HELP 定义。

EFI_STATUS EFIAPI MyShellCommandLibConstructor(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable)
{
    gMyShellCommandHiiHandle = HiiAddPackages (&gMyShellCommandGuid, ImageHandle, MyShellCommandLibStrings, NULL);
    if(gMyShellCommandHiiHandle != NULL)
    {
        ShellCommandRegisterCommandName(L"mycmd", MyShellCommand, MyShellCommandGetFileName, 0, L"", FALSE, gMyShellCommandHiiHandle, STRING_TOKEN(STR_GET_MYCMD_HELP));
    }
    return EFI_SUCCESS;
}

有兴趣的朋友可以使用这个框架自行扩展 UEFI Shell。

参考:

  1. https://www.lab-z.com/stu90shc/
  2. http://www.lab-z.com/stu88/

TrustedInstaller 无法删除目录和文件的解决方法

最近在测试的时候多次遇到了文件无法删除的情况

经过研究可以使用下面的方法进行删除:

1.运行Regfix.reg 文件将设置导入注册表

2.选中文件或者目录后,鼠标右键菜单会出现“Take Ownership”的选项,选中执行即可

3.运行UninstallRegfix.reg 可以去掉上述的菜单选项

下载:

亲测有效,推荐有需要的朋友试试。

参考:

1.https://thegeekpage.com/how-to-delete-files-protected-by-trustedinstaller-in-windows-10/

EDK2 202411 来了

去年11月份,EDK2 202411正式发布在:

https://github.com/tianocore/edk2/releases/tag/edk2-stable202411

从 History 来看,只是有一些功能性改进:

和之前类似,这里放上一个完整版,补全了所有的三方库,大小是467MB 左右。下载之后,运行过一次 edksetup.bat forcerebuild 编译了需要用的工具,否则直接使用可能会遇到一些工具无法找到的错误。

链接:https://pan.baidu.com/s/1JjJOr7MWxxUsj0ip1Leg2Q?pwd=LABZ

提取码: LABZ

个人建议:除非有特别明确的目的,否则没有必要追求最新的版本, 所谓 “小车能跑只管推”。

三亚 外一篇:沙滩

我在三亚居住的酒店距离大海非常近,早晨起来我一个人出门去了海边。春节时间到三亚最重要的问题是保暖,千万不要因为感觉一下子暖和起来就减去衣物。作为一个东北人,我对温度还是非常敏感的,稍微感觉寒冷就会添加衣物。而我的老婆则是“非常抗冻”的湖北人,于是到达三亚的第二天,她穿的很少和我们一起去了一下南山寺。刚一下车她就开始后悔穿的过少。我都戏称门上的“二不”是专门说她的。第三天,她就开始不舒服头疼,后面更是在九所的宾馆一直“趴窝”了。

沙滩的沙子很细腻,这边远离市区,加上比较早,所以没有多少人。

太阳还没有升起,云高海阔如是:

沙滩上有无数小洞穴:

洞很圆,很有规则的形状,是小螃蟹挖出来的。打一个洞,然后藏身于此。海滩上有小朋友拿着铲子对准洞穴,斜着挖下去,运气好的话马上就会有小螃蟹慌张的逃出来:

刚好在海滩上遇到一群人,腰上缠绕着绳子,绳子末端带有一个圆球。起初我以为是要进行什么游戏。

等他们列队开工成我才知道原来是一种古老的捕鱼方式。首先,海里面有一艘渔船,下网,然后网的一头捆扎住绳子交给岸上的人。接下来这些人用腰间的绳子连接到这个网的绳子上。缠绕的方式也非常简单:用球在绳子上一丢很快就缠绕好了,然后用腰部的力量拉拽着网绳。拉拽的过程中完全凭借腰部和身体的力量完全不用手,可以一边吸烟一边工作着。前面的人用力拉拽,向着远离大海的方向退去,退倒最后再将带着球的绳子解下来,再走到最前面缠绳子上重复这样的动作。这样我怀疑最早的拔河比赛是否也发源于此。后来查了一下,一百年前,拔河是奥运比赛项目,后来因为英国人创造性的作弊导致这个项目最终被取消了。

渔网很长,我看了半个多小时也没有到头的意思,后面就回去酒店了。路上偶然看到了波罗蜜,原来它是这样长在树上的:

细枝硕果:

PVD:绝对值鼠标

我们通常使用的鼠标发送的都是相对坐标,比如:输出 X=100,Y=200, 意思是通知系统将鼠标从目前的位置移动(100,200)个单位。此外,Windows 还有一个鼠标优化机制,比如,你的鼠标输出范围是 +/- 127, 如果你的屏幕宽度是 1920, 经过优化之后无需滑动 1920/127 次才能将鼠标指针从最左边移动到最右边。

这次带来的PVD (Physical Virtual Device)是一款绝对值鼠标,它模拟了一个绝对值鼠标,能够将从USB串口输入的数据转化为绝对值鼠标数据发送出来。这样,可以方便的实现鼠标点击屏幕上的任意位置。

硬件部分使用和上一次设计相同【参考1】,核心是 WCH出品的 CH554e单片机。

代码是 Arduino 来实现的,屏幕左上角是 (0,0), 输出坐标为 0-32767。实践表明:送出来的数据和屏幕分辨率存在定比例关系。比如,在 1920*1024屏幕上,如果想让鼠标移动到 (300, 200)的位置,那么需要设备输出(300/1920 *32768, 200/1024 *32768)这样的数据。

主程序代码如下:

#ifndef USER_USB_RAM
#error "This example needs to be compiled with a USER USB setting"
#endif

#include <WS2812.h>
#include "src/CdcHidCombo/USBCDC.h"
#include "src/CdcHidCombo/USBHIDKeyboardMouse.h"

#define NUM_LEDS 1
#define COLOR_PER_LEDS 3
#define NUM_BYTES (NUM_LEDS*COLOR_PER_LEDS)

__xdata uint8_t ledData[NUM_BYTES];

#define  KeyboardReportID  0x01
#define  rMouseReportID    0x02
#define  aMouseReportID    0x03
#define  OnBoardLED        0x04

// Data format
// Keyboard(Total 9 bytes): 01(ReportID 01) + Keyboard data (8 Bytes)
// Mouse(Total 5 bytes): 02(ReportID 02) + Mouse Data (4 Bytes)
uint8_t recvStr[9];
uint8_t recvStrPtr = 0;
unsigned long Elsp;

void setup() {
  USBInit();
  Serial0_begin(115200);
  delay(1000);
  Serial0_print("start");
  Elsp=0;
}

void loop() {
  while (USBSerial_available()) {
    uint8_t serialChar = USBSerial_read();
    recvStr[recvStrPtr++] = serialChar;
    if (recvStrPtr == 10) {
      for (uint8_t i = 0; i < 9; i++) {
        Serial0_write(recvStr[i]);
      }      
      if (recvStr[0] == KeyboardReportID) { // Keyboard
        USB_EP3_send(recvStr, 9);
      }
      if (recvStr[0] == rMouseReportID) {
        USB_EP3_send(recvStr, 5); // Relative Mouse
      }
      if (recvStr[0] == aMouseReportID) {
        USB_EP3_send(recvStr, 7); // Absolute Mouse
      }      
      if (recvStr[0] == OnBoardLED) {
        set_pixel_for_GRB_LED(ledData, 0, recvStr[1], recvStr[2], recvStr[3]); 
        neopixel_show_P1_5(ledData, NUM_BYTES);  
      }



      recvStrPtr = 0;
    }
    Elsp=millis();
  }
  // If there is no data in 100ms, clear the receive buffer
  if (millis()-Elsp>100) {
      recvStrPtr = 0;
      Elsp=millis();
    }
}

如果USB CDC 收到以 aMouseReportID 起始的9个字节,那么会将数据直接转到绝对值鼠标端点然后发送给主机。

VS2019 编写一个上位机程序进行测试,代码如下:

// CDC_vKBMSTest.cpp : This file contains the 'main' function. Program execution begins and ends there.
//

#include <windows.h>
#include <SetupAPI.h>
#include <tchar.h>
#include <iostream>
#include <cstring>
#include <atlstr.h>

#pragma comment(lib, "Setupapi.lib")

#define MY_USB_PID_VID	_T("VID_1209&PID_C55C")
#define SCREENWIDTH 1920
#define SCREENHEIGHT 1200
int Port;

class ComPortException : public std::exception {
public:
	ComPortException(DWORD errorCode) : errorCode(errorCode) {}

	DWORD getErrorCode() const {
		return errorCode;
	}

private:
	DWORD errorCode;
};

// 对串口portName 发送数据
// 无法打开串口返回 1
// 无法设置串口参数 2
void SendToComPort(const int port, const char* data) {
	int Result = 0;
	HANDLE hCom = INVALID_HANDLE_VALUE;
	TCHAR portName[10]; // 用于存储 "COMp" 字符串

// 将整数 p 转换为 "COMp" 字符串
#ifdef UNICODE
	swprintf(portName, 10, _T("\\\\.\\COM%d"), port);
#else
	sprintf(portName, "COM%d", port);
#endif
	try {
		// 打开串口
		hCom = CreateFile(portName,
			GENERIC_READ | GENERIC_WRITE,
			0,
			NULL,
			OPEN_EXISTING,
			0,
			NULL);

		if (hCom == INVALID_HANDLE_VALUE) {
			throw ComPortException(GetLastError());
		}

		// 设置串口参数
		DCB dcb;
		SecureZeroMemory(&dcb, sizeof(DCB));
		dcb.DCBlength = sizeof(DCB);

		if (!GetCommState(hCom, &dcb)) {
			throw ComPortException(GetLastError());
		}

		dcb.BaudRate = CBR_115200;  // 波特率
		dcb.ByteSize = 8;         // 数据位
		dcb.StopBits = ONESTOPBIT; // 停止位
		dcb.Parity = NOPARITY;    // 校验位

		if (!SetCommState(hCom, &dcb)) {
			throw ComPortException(GetLastError());
		}

		// 设置超时参数
		COMMTIMEOUTS timeouts;
		timeouts.ReadIntervalTimeout = 50;
		timeouts.ReadTotalTimeoutConstant = 50;
		timeouts.ReadTotalTimeoutMultiplier = 10;
		timeouts.WriteTotalTimeoutConstant = 50;
		timeouts.WriteTotalTimeoutMultiplier = 10;

		if (!SetCommTimeouts(hCom, &timeouts)) {
			throw ComPortException(GetLastError());
		}

		// 发送数据
		DWORD bytesWritten;
		if (!WriteFile(hCom, data, 10, &bytesWritten, NULL)) {
			std::cerr << "Failed to write to COM port." << std::endl;
		}
		else {
			std::cout << "Successfully sent data to COM port: [" << port << "]" << std::endl;
		}

		for (int i = 0; i < 10; i++) {
			printf("%02x ", data[i]&0xFF);
		}
		printf("\n");
		// 关闭串口
		if (hCom != INVALID_HANDLE_VALUE) {
			CloseHandle(hCom);
		}
	}
	catch (const ComPortException& ex) {
		std::cerr << "Error: " << ex.getErrorCode() << std::endl;
		if (hCom != INVALID_HANDLE_VALUE) {
			CloseHandle(hCom);
		}
	}

}

/************************************************************************/
/* 根据USB描述信息字符串中读取
/************************************************************************/
int MTGetPortFromVidPid(CString strVidPid)
{
	// 获取当前系统所有使用的设备
	int					nPort = -1;
	int					nStart = -1;
	int					nEnd = -1;
	int					i = 0;
	CString				strTemp, strName;
	DWORD				dwFlag = (DIGCF_ALLCLASSES | DIGCF_PRESENT);
	HDEVINFO			hDevInfo = INVALID_HANDLE_VALUE;
	SP_DEVINFO_DATA		sDevInfoData;
	TCHAR				szDis[2048] = { 0x00 };// 存储设备实例ID
	TCHAR				szFN[MAX_PATH] = { 0x00 };// 存储设备实例属性
	DWORD				nSize = 0;

	// 准备遍历所有设备查找USB
	hDevInfo = SetupDiGetClassDevs(NULL, L"USB", NULL, dwFlag);
	if (INVALID_HANDLE_VALUE == hDevInfo)
		goto STEP_END;

	// 开始遍历所有设备
	memset(&sDevInfoData, 0x00, sizeof(SP_DEVICE_INTERFACE_DATA));
	sDevInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
	for (i = 0; SetupDiEnumDeviceInfo(hDevInfo, i, &sDevInfoData); i++)
	{
		nSize = 0;

		// 无效设备
		if (!SetupDiGetDeviceInstanceId(hDevInfo, &sDevInfoData, szDis, sizeof(szDis), &nSize))
			goto STEP_END;

		// 根据设备信息寻找VID PID一致的设备
		strTemp.Format(_T("%s"), szDis);
		strTemp.MakeUpper();
		if (strTemp.Find(strVidPid, 0) == -1)
			continue;

		// 查找设备属性
		nSize = 0;
		SetupDiGetDeviceRegistryProperty(hDevInfo, &sDevInfoData,
			SPDRP_FRIENDLYNAME,
			0, (PBYTE)szFN,
			sizeof(szFN),
			&nSize);

		// "XXX Virtual Com Port (COM7)"
		strName.Format(_T("%s"), szFN);
		_tprintf(_T("%s"), szFN);
		if (strName.IsEmpty())
			//goto STEP_END;
			continue;

		// 寻找串口信息
		nStart = strName.Find(_T("(COM"), 0);
		nEnd = strName.Find(_T(")"), 0);
		if (nStart == -1 || nEnd == -1)
			//goto STEP_END;
			continue;

		strTemp = strName.Mid(nStart + 4, nEnd - nStart - 4);
		nPort = _ttoi(strTemp);

	}
STEP_END:

	// 关闭设备信息集句柄
	if (hDevInfo != INVALID_HANDLE_VALUE)
	{
		SetupDiDestroyDeviceInfoList(hDevInfo);
		hDevInfo = INVALID_HANDLE_VALUE;
	}

	return nPort;
}

int ScreenX2Abs(int X) {
	return (X* 32768 / SCREENWIDTH);
}
int ScreenY2Abs(int Y) {
	return (Y  * 32768 / SCREENHEIGHT);
}

void ChangeColor(
	int X,
	int Y
) {
	char Data[10];

	memset(Data, 0, sizeof(Data));
	Data[0] = 3; // 绝对值鼠标
	Data[1] = 1; // 点击
	Data[2] = ScreenX2Abs(X) & 0xFF;
	Data[3] = (ScreenX2Abs(X) >> 8) & 0xFF;
	Data[4] = ScreenY2Abs(Y) & 0xFF;
	Data[5] = (ScreenY2Abs(Y) >> 8) & 0xFF;
	SendToComPort(Port, (char*)&Data);
	Sleep(100);
	memset(Data, 0, sizeof(Data));
	Data[0] = 3; // 绝对值鼠标
	Data[1] = 0; // 点击
	Data[2] = ScreenX2Abs(X) & 0xFF;
	Data[3] = (ScreenX2Abs(X) >> 8) & 0xFF;
	Data[4] = ScreenY2Abs(Y) & 0xFF;
	Data[5] = (ScreenY2Abs(Y) >> 8) & 0xFF;
	SendToComPort(Port, (char*)&Data);
	Sleep(100);
}

void LedColor(
	int Color
) {
	char Data[10];

	memset(Data, 0, sizeof(Data));
	Data[0] = 4; // LED
	Data[1] = Color&0xFF; // 点击
	Data[2] = (Color>>8) & 0xFFF;
	Data[3] = (Color >>16) & 0xFF;

	SendToComPort(Port, (char*)&Data);
}

void DrawRect(
	int StartX,
	int StartY,
	int Width,
	int Height,
	int Dx,
	int Dy
) {
	char Data[10];

	//从左到右横线
	//line(StartX, StartY, StartX + Width, StartY);
	memset(Data, 0, sizeof(Data));
	Data[0] = 3; // 绝对值鼠标
	Data[1] = 1; // 点击
	Data[2] = ScreenX2Abs(StartX) & 0xFF;
	Data[3] = (ScreenX2Abs(StartX) >> 8) & 0xFF;
	Data[4] = ScreenY2Abs(StartY) & 0xFF;
	Data[5] = (ScreenY2Abs(StartY) >> 8) & 0xFF;
	SendToComPort(Port, (char*)&Data);
	Sleep(100);

	Data[0] = 3; // 绝对值鼠标
	Data[1] = 1; // 点击
	Data[2] = ScreenX2Abs(StartX+Width) & 0xFF;
	Data[3] = (ScreenX2Abs(StartX+Width) >> 8) & 0xFF;
	Data[4] = ScreenY2Abs(StartY) & 0xFF;
	Data[5] = (ScreenY2Abs(StartY) >> 8) & 0xFF;
	SendToComPort(Port, (char*)&Data);
	Sleep(100);

	Data[0] = 3; // 绝对值鼠标
	Data[1] = 0; // 抬起
	Data[2] = ScreenX2Abs(StartX + Width) & 0xFF;
	Data[3] = (ScreenX2Abs(StartX + Width) >> 8) & 0xFF;
	Data[4] = ScreenY2Abs(StartY) & 0xFF;
	Data[5] = (ScreenY2Abs(StartY) >> 8) & 0xFF;
	SendToComPort(Port, (char*)&Data);
	Sleep(100);

	//从上到下,竖线
	//line(StartX + Width, StartY,StartX+Width,StartY+Height);
	memset(Data, 0, sizeof(Data));
	Data[0] = 3; // 绝对值鼠标
	Data[1] = 1; // 点击
	Data[2] = ScreenX2Abs(StartX+Width) & 0xFF;
	Data[3] = (ScreenX2Abs(StartX + Width) >> 8) & 0xFF;
	Data[4] = ScreenY2Abs(StartY) & 0xFF;
	Data[5] = (ScreenY2Abs(StartY) >> 8) & 0xFF;
	SendToComPort(Port, (char*)&Data);
	Sleep(100);

	Data[0] = 3; // 绝对值鼠标
	Data[1] = 1; // 点击
	Data[2] = ScreenX2Abs(StartX + Width) & 0xFF;
	Data[3] = (ScreenX2Abs(StartX + Width) >> 8) & 0xFF;
	Data[4] = ScreenY2Abs(StartY+Height) & 0xFF;
	Data[5] = (ScreenY2Abs(StartY+Height) >> 8) & 0xFF;
	SendToComPort(Port, (char*)&Data);
	Sleep(100);

	Data[0] = 3; // 绝对值鼠标
	Data[1] = 0; // 抬起
	Data[2] = ScreenX2Abs(StartX + Width) & 0xFF;
	Data[3] = (ScreenX2Abs(StartX + Width) >> 8) & 0xFF;
	Data[4] = ScreenY2Abs(StartY + Height) & 0xFF;
	Data[5] = (ScreenY2Abs(StartY + Height) >> 8) & 0xFF;
	SendToComPort(Port, (char*)&Data);
	Sleep(100);

	//从右到左,横线
	//line(StartX + Width, StartY + Height,StartX+Dx,StartY+Height);
	memset(Data, 0, sizeof(Data));
	Data[0] = 3; // 绝对值鼠标
	Data[1] = 1; // 点击
	Data[2] = ScreenX2Abs(StartX + Width) & 0xFF;
	Data[3] = (ScreenX2Abs(StartX + Width) >> 8) & 0xFF;
	Data[4] = ScreenY2Abs(StartY+Height) & 0xFF;
	Data[5] = (ScreenY2Abs(StartY+Height) >> 8) & 0xFF;
	SendToComPort(Port, (char*)&Data);
	Sleep(100);

	Data[0] = 3; // 绝对值鼠标
	Data[1] = 1; // 点击
	Data[2] = ScreenX2Abs(StartX + Dx) & 0xFF;
	Data[3] = (ScreenX2Abs(StartX + Dx) >> 8) & 0xFF;
	Data[4] = ScreenY2Abs(StartY + Height) & 0xFF;
	Data[5] = (ScreenY2Abs(StartY + Height) >> 8) & 0xFF;
	SendToComPort(Port, (char*)&Data);
	Sleep(100);

	Data[0] = 3; // 绝对值鼠标
	Data[1] = 0; // 抬起
	Data[2] = ScreenX2Abs(StartX + Dx) & 0xFF;
	Data[3] = (ScreenX2Abs(StartX + Dx) >> 8) & 0xFF;
	Data[4] = ScreenY2Abs(StartY + Height) & 0xFF;
	Data[5] = (ScreenY2Abs(StartY + Height) >> 8) & 0xFF;
	SendToComPort(Port, (char*)&Data);
	Sleep(100);

	//从下到上竖线
	//line(StartX + Dx, StartY + Height, StartX + Dx, StartY + Dy);
	memset(Data, 0, sizeof(Data));
	Data[0] = 3; // 绝对值鼠标
	Data[1] = 1; // 点击
	Data[2] = ScreenX2Abs(StartX + Dx) & 0xFF;
	Data[3] = (ScreenX2Abs(StartX + Dx) >> 8) & 0xFF;
	Data[4] = ScreenY2Abs(StartY + Height) & 0xFF;
	Data[5] = (ScreenY2Abs(StartY + Height) >> 8) & 0xFF;
	SendToComPort(Port, (char*)&Data);
	Sleep(100);

	Data[0] = 3; // 绝对值鼠标
	Data[1] = 1; // 点击
	Data[2] = ScreenX2Abs(StartX + Dx) & 0xFF;
	Data[3] = (ScreenX2Abs(StartX + Dx) >> 8) & 0xFF;
	Data[4] = ScreenY2Abs(StartY + Dy) & 0xFF;
	Data[5] = (ScreenY2Abs(StartY + Dy) >> 8) & 0xFF;
	SendToComPort(Port, (char*)&Data);
	Sleep(100);

	Data[0] = 3; // 绝对值鼠标
	Data[1] = 0; // 抬起
	Data[2] = ScreenX2Abs(StartX + Dx) & 0xFF;
	Data[3] = (ScreenX2Abs(StartX + Dx) >> 8) & 0xFF;
	Data[4] = ScreenY2Abs(StartY + Dy) & 0xFF;
	Data[5] = (ScreenY2Abs(StartY + Dy) >> 8) & 0xFF;
	SendToComPort(Port, (char*)&Data);
	Sleep(100);
}

int main()
{

	printf("%d[%x]  %d[%x]\n", ScreenX2Abs(100), ScreenX2Abs(100), ScreenY2Abs(300), ScreenY2Abs(300));
	printf("Virutal KB MS Test\n");
	Port = MTGetPortFromVidPid(MY_USB_PID_VID);
	if (Port == -1) {
		printf("No device is found\n");
		goto EndProgram;
	}
	else {
		printf("Found COM%d\n",Port);
	}
	Sleep(5000);
	for (int i = 0; i < 8; i++) {
		DrawRect(100+20*i, 300+20*i, SCREENWIDTH - 200-20*i*2, SCREENHEIGHT - 500-20*i*2, 20, 20);
		if ((i % 3) == 0) {
			LedColor(0x01);
		}
		if ((i % 3) == 1) {
			LedColor(0x0100);
		}
		if ((i % 3) == 2) {
			LedColor(0x010000);
		}
	}
	
	ChangeColor(1329,125);
	for (int i = 8; i < 18; i++) {
		DrawRect(100 + 20 * i, 300 + 20 * i, SCREENWIDTH - 200 - 20 * i * 2, SCREENHEIGHT - 500 - 20 * i * 2, 20, 20);
		if ((i % 3) == 0) {
			LedColor(0x01);
		}
		if ((i % 3) == 1) {
			LedColor(0x0100);
		}
		if ((i % 3) == 2) {
			LedColor(0x010000);
		}
	}


EndProgram:
	printf("End\n");
	getchar();
}

这个代码的作用是在画笔中绘制蛇形线,在绘制过程中还有更换颜色的动作。

工作的视频: 【PVD 计划:绝对值鼠标测试】

参考:

1. https://mc.dfrobot.com.cn/thread-323494-1-1.html

海南:石碌镇

离开九所之后,我们继续行程。乘坐高铁到达棋子湾站,然后乘车前往了昌江黎族自治县下面的石碌镇。这里距离棋子湾站大约30多公里。石碌镇在地图上有火车线,应该是货运线,并不能载客。

当地气温比三亚九所要低一些,阴天的次数也多一些。我母亲在当地租住的房屋一个完全向西的8楼民居,靠近当地的民族中学,房租每月1500。

小区是高层,最高24楼。正好是春节,大多数店铺都歇业回家过节去了。

对于我们来说,这里仍然是热带风情

这是一颗芒果树

尚未成熟的芒果:

居住的小区旁边是文化公园,吃过饭去转转,一条街划出了一个夜市,人头攒动有卖各种水果的小贩。

母亲提到这边晚上虽然热闹,但是不知道什么路灯给人昏暗的感觉。我走在街上确实也有这样的感觉。每个摊贩都准备了自己的台灯,照亮着摊位。

听母亲介绍我还去了一下当地的昌江黎族自治县宣传文化中心。当地的刊物《昌江文艺》:

其中有一篇《铁城旧事》作者“林元康”,简单介绍了石碌的历史。“在清代乾隆嘉年间,此地采铜,铜矿石氧化后变绿,而绿与碌同音,因此得名。”文化和经济是密切相关的,能出版这样的刊物从侧面也可以证明当地的经济水平应该不错。

我的父亲是一名文字爱好者,他的专业是地质测绘,但是参加工作没多久就转去做宣传口,也算是得偿所愿。之前我并不理解,因为在某些意义上来说Propaganda是一个带有贬义的词语。但是随着年纪的增长,我逐渐意识到,这样工作的意义在于构建一个想象的共同体增加凝聚力,是现实文化的一部分,甚至意味着重新定义规则。比如,韩国人注册了“端午节”,当中国人质疑的时候他们就会说申请的是当地的“端午节”。但这个并不会影响他们会对外介绍这是正宗“端午节”,让外国人将这个节日和韩国联系在一起。再比如,在韩国人和越南人的支持下,越来越多的国家使用 “Lunar New Year”来替代“Chinese New Year” 的称呼,更可以看作是以削弱中国文化影响力为目标的行为。

不过想想,对于韩国人来说,这样的操作并不意外:

Koreansmas