AWTK 嵌入式Linux平台实现多点触控缩放旋转以及触点丢点问题解决

article/2025/6/11 5:39:01

前言

最近涉及海图的功能交互,多点触摸又开始找麻烦。

在PC/Web平台awtk是通过底层的sdl2库来实现多点触摸,但是在嵌入式Linux平台,可能是考虑到性能原因,awtk并没有采用sdl库来做事件处理,而是自己实现一个awtk-linux-fb来做适配,多点触摸的相关逻辑必须自己适配。

去年11月的时候,匆忙赶工,自己适配了一份tslib的代码,思路是循环线程内读取触点数据后,直接调用awtk自带的一个multi_gesture.inc文件去计算距离和旋转角度,在应用层注册EVT_MULTI_GESTURE事件。

static ret_t tslib_dispatch_one_event(run_info_t* info) {#ifdef MT_TOUCH_ENABLEint ret = -1;if (info->ts != NULL) {ret = ts_read_mt(info->ts, info->samp_mt, info->max_slots, info->read_samples);}uint8_t event_number = 0, down_number = 0;...int max_slots = info->max_slots;// note: down, up only trigger once(ET), move will be keep trigger(LT)for (int i = 0; i < max_slots; i++) {// printf(YELLOW "sample %d - %ld.%06ld -" RESET " (slot %d) %6d %6d %6d\n",// 0,// info->samp_mt[0][i].tv.tv_sec,// info->samp_mt[0][i].tv.tv_usec,// info->samp_mt[0][i].slot,// info->samp_mt[0][i].x,// info->samp_mt[0][i].y,// info->samp_mt[0][i].pressure);if (!(info->samp_mt[0][i].valid & TSLIB_MT_VALID)){//for boards that no clear pressure when slot is invaild, need to do it manuallyif(!s_points[i].type == EVT_MULTI_TOUCH_DOWN){info->samp_mt[0][i].pressure = 0;}continue;}event_number++;}for (int i = 0; i < CT_MAX_TOUCH; i++){s_points[i].touch_id = 0;s_points[i].finger_id = i;if(info->samp_mt[0][i].pressure > 0) {down_number++;s_points[i].type = (s_points[i].x == info->samp_mt[0][i].x && s_points[i].y == info->samp_mt[0][i].y) ? EVT_MULTI_TOUCH_DOWN : EVT_MULTI_TOUCH_MOVE;s_points[i].x = info->samp_mt[0][i].x;s_points[i].y = info->samp_mt[0][i].y;}else{s_points[i].type = EVT_MULTI_TOUCH_UP;s_points[i].x = 0;s_points[i].y = 0;}   }if(event_number == 1 && (info->last_down_number == 0 || info->last_down_number == 1)){//单点触摸...tslib_dispatch(info);}else{//多点触摸main_loop_t *loop = (main_loop_t*)info->dispatch_ctx;//multi_gesture.inc提供的函数multi_gesture_post_event_from_points(loop, touch_points, down_number, s_points);}
...

后面实测multi_gesture.inc完全不堪用,机器上双指缩放判定经常失准,双指拉大,会出现一会放大一会缩小的情况,multi_gesture.inc的业务代码我没有细看,但我估计逻辑肯定是有问题的,至少在现在的机器上无法使用。

适配层设计

只能寻找新的触摸方案了,这时候老板指出来我对触摸屏的理解有误,我一开始的想法是手指一触摸屏幕,立刻会在应用层生成一份即时的完整的触点数组数据对象,通过这个对象来获取各触点坐标,状态(按下,移动,弹起),按下手指的数量。后面才知道,触摸屏是逐个去解析按下的各个手指的数据然后处理的,并不是一次就能全部读取到,也就是说,我想像的这种数据对象的组装只能到应用层去做而不是适配层去做,之前的思路相当于把解析和业务逻辑都在适配层做,结果业务一复杂就变得不敷使用了。

照着这种思路,应该是适配层只需要把所有手指的数据一个个上报上去,业务层实现实际逻辑,这样适配层的代码逻辑会更加简单,那么AWTK有没有代表单个手指的数据?

查阅AWTK代码, 发现有一个touch_event正好符合要求,很幸运也很讽刺,awtk官方在去年12月4日的更新里面已经支持在awtk-linux-fb对touch_event事件上报,还在awtk-web整了一个多点触摸的演示demo,里面的finger_status_t已经把我设想的数据对象的功能给完成了,我累死累活自己适配了一版触摸,结果人家一个月后自己就整好了一个更好的方案,我还一直没有注意到,惭愧。。。

不过项目紧急,有现成的轮子直接拿来用总是好事,重改适配层,这次只需要把ts_read_mt读到的事件封装成touch_event事件直接丢给队列即可:

#define CT_MAX_TOUCH 10
static multi_touch_point_event_t s_points[CT_MAX_TOUCH];ret_t my_main_loop_post_touch_event(main_loop_t* l, event_type_t event_type, touch_event_t* event) {event_queue_req_t r;touch_event_t evt;main_loop_simple_t* loop = (main_loop_simple_t*)l;memset(&r, 0x00, sizeof(r));memset(&evt, 0x00, sizeof(multi_gesture_event_t));return_value_if_fail(loop != NULL, RET_BAD_PARAMS);memcpy(&evt, event, sizeof(touch_event_t));evt.e.type = event_type;evt.e.time = time_now_ms();evt.e.size = sizeof(touch_event_t);r.touch_event = evt;return main_loop_queue_event(l, &r);
}static ret_t tslib_dispatch_one_event(run_info_t* info) {....// note: down, up only trigger once(ET), move will be keep trigger(LT)for (int i = 0; i < max_slots; i++) {if (!(info->samp_mt[0][i].valid & TSLIB_MT_VALID)){continue;}if(info->samp_mt[0][i].pressure > 0){down_number++;if(s_points[i].type == 0 || s_points[i].type == EVT_TOUCH_UP){s_points[i].type = EVT_TOUCH_DOWN;}else{s_points[i].type = EVT_TOUCH_MOVE;}} else{s_points[i].type = EVT_TOUCH_UP;}s_points[i].finger_id = info->samp_mt[0][i].slot;s_points[i].x = info->samp_mt[0][i].x;s_points[i].y = info->samp_mt[0][i].y;event_number++;main_loop_t *loop = (main_loop_t*)info->dispatch_ctx;touch_event_t touch_event;touch_event_init(&touch_event, s_points[i].type, NULL, 0, info->samp_mt[0][i].slot, info->samp_mt[0][i].x / (double)info->max_x, info->samp_mt[0][i].y / (double)info->max_y, info->samp_mt[0][i].pressure);my_main_loop_post_touch_event(loop, s_points[i].type, &touch_event);...

触点丢失事件

乐极生悲,接下来的一个坑卡了一周都无法解决, 发现应用程序一旦负担比较高,比如渲染复杂图形或者事件处理极为频繁的时候,touch_up的事件经常会被打断。最后问了微信群,才知道是awtk的活动队列处理不过来导致丢事件,把main_loop_simple.h的MAIN_LOOP_QUEUE_SIZE宏从默认的20调高到100,重新编译awtk-linux-fb和应用程序后,问题解决。

对于之前的那个测试demo, 它管理了一个触点对象数组s_fingers_status,一旦检测到手指按下就会生成一个finger_status_t类型的触点对象并加入到s_fingers_status 中,finger_status_t内部也维护了一个point数组,在手指移动的时候就会将手指移动的即时坐标数据加入到数组中,用于on_paint事件的画线测试,然后在手指弹起时,该触点对象会被从s_fingers_status中移除并销毁,如果touch_up事件不上报的话这个事件就会一直留在s_fingers_status里面,导致无法正常获取正确的按下手指数量,出问题的手指对象也会一直停留在move的状态,无法恢复。

on_touch_up: 3 size=0
on_touch_down : 1 size=1 460 103
on_touch_down : 3 size=2 591 214
on_touch_move: 1 size=2 459 105
on_touch_move: 3 size=2 591 214
on_touch_move: 1 size=2 459 112
on_touch_move: 3 size=2 591 219
on_touch_move: 1 size=2 458 121
on_touch_move: 3 size=2 590 225
on_touch_move: 1 size=2 458 139
on_touch_move: 3 size=2 589 237
on_touch_move: 1 size=2 459 162
on_touch_move: 3 size=2 587 251
on_touch_down : 2 size=3 295 112
on_touch_move: 2 size=3 295 113
on_touch_move: 2 size=3 296 118
on_touch_move: 2 size=3 298 125
on_touch_move: 2 size=3 302 143
on_touch_move: 1 size=3 461 193
on_touch_move: 2 size=3 308 166
on_touch_move: 3 size=3 585 272
on_touch_move: 1 size=3 464 228
on_touch_move: 2 size=3 318 200
on_touch_move: 3 size=3 582 296
on_touch_down : 0 size=4 137 279
on_touch_move: 0 size=4 137 280
on_touch_move: 0 size=4 144 294
on_touch_move: 0 size=4 154 312
on_touch_move: 0 size=4 173 348
on_touch_move: 0 size=4 195 394
on_touch_move: 1 size=4 468 268
on_touch_move: 1 size=4 493 388
on_touch_move: 2 size=4 378 391
on_touch_move: 1 size=4 506 420
on_touch_up: 2 size=3
on_touch_move: 1 size=3 518 447
on_touch_move: 1 size=3 525 466
on_touch_move: 1 size=3 525 481
on_touch_up: 1 size=2

之前没找到问题根源的时候就隐约觉得问题跟机器的性能有关,因为测试demo在公司的开发板上两指到五指都正常,但是到了自己住处, 用百问网的imx6ull开发板一测试很快就出现丢点问题,后面又在适配层尝试限制touch_move事件的频率,改为30ms上报一次touch_move事件,发现有一定的降低丢点概率的效果(手指一多还是会丢点),但是仍旧未往事件队列本身的处理能力去设想,更没有想到在awtk库里面可以调这个事件队列大小,GUI开发还有很多基础知识需要完善。

最终代码

tslib_thread.c

/*** File:   tslib_thread.c* Author: AWTK Develop Team* Brief:  thread to handle touch screen events** Copyright (c) 2018 - 2025 Guangzhou ZHIYUAN Electronics Co.,Ltd.** This program is distributed in the hope that it will be useful,* but WITHOUT ANY WARRANTY; without even the implied warranty of* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the* License file for more details.**//*** History:* ================================================================* 2018-09-07 Li XianJing <xianjimli@hotmail.com> created**/#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
#include "tslib.h"
#include "tkc/mem.h"
#include "tkc/utils.h"
#include "tkc/thread.h"
#include "base/keys.h"#include "tslib_thread.h"
#include <linux/input.h>
#include "multi_gesture.inc"typedef struct _run_info_t {int32_t max_x;int32_t max_y;struct tsdev* ts;void* dispatch_ctx;char* filename;input_dispatch_t dispatch;event_queue_req_t req;struct ts_sample_mt **samp_mt;struct input_absinfo slot;int32_t user_slots;int32_t max_slots;int read_samples;int last_down_number;
} run_info_t;#define RESET   "\033[0m"
#define RED     "\033[31m"
#define GREEN   "\033[32m"
#define BLUE    "\033[34m"
#define YELLOW  "\033[33m"#define CT_MAX_TOUCH 10
static multi_gesture_touch_points_t* touch_points = NULL;
static multi_touch_point_event_t s_points[CT_MAX_TOUCH];static ret_t tslib_dispatch(run_info_t* info) {ret_t ret = RET_FAIL;char message[MAX_PATH + 1] = {0};// tk_snprintf(message, sizeof(message) - 1, "ts[%s]", info->filename);ret = info->dispatch(info->dispatch_ctx, &(info->req), message);info->req.event.type = EVT_NONE;return ret;
}ret_t my_main_loop_post_touch_event(main_loop_t* l, event_type_t event_type, touch_event_t* event) {event_queue_req_t r;touch_event_t evt;main_loop_simple_t* loop = (main_loop_simple_t*)l;memset(&r, 0x00, sizeof(r));memset(&evt, 0x00, sizeof(multi_gesture_event_t));return_value_if_fail(loop != NULL, RET_BAD_PARAMS);memcpy(&evt, event, sizeof(touch_event_t));evt.e.type = event_type;evt.e.time = time_now_ms();evt.e.size = sizeof(touch_event_t);r.touch_event = evt;return main_loop_queue_event(l, &r);
}static ret_t tslib_dispatch_one_event(run_info_t* info) {int ret = -1;if (info->ts != NULL) {ret = ts_read_mt(info->ts, info->samp_mt, info->max_slots, info->read_samples);}uint8_t event_number = 0, down_number = 0;event_queue_req_t* req = &(info->req);if (ret == 0) {log_warn("%s:%d: get tslib data failed, filename=%s\n", __func__, __LINE__, info->filename);sleep(1);return RET_OK;} else if (ret < 0) {sleep(2);if (access(info->filename, R_OK) == 0) {if (info->ts != NULL) {ts_close(info->ts);}info->ts = ts_open(info->filename, 0);return_value_if_fail(info->ts != NULL, RET_OK);ts_config(info->ts);if (info->ts == NULL) {log_debug("%s:%d: open tslib failed, filename=%s\n", __func__, __LINE__, info->filename);perror("print tslib: ");} else {log_debug("%s:%d: open tslib successful, filename=%s\n", __func__, __LINE__,info->filename);}}return RET_OK;}int max_slots = info->max_slots;// note: down, up only trigger once(ET), move will be keep trigger(LT)for (int i = 0; i < max_slots; i++) {if (!(info->samp_mt[0][i].valid & TSLIB_MT_VALID)){continue;}// printf(YELLOW "BSP sample %d - %ld.%06ld -" RESET " (slot %d) %6d %6d %6d\n",// 0,// info->samp_mt[0][i].tv.tv_sec,// info->samp_mt[0][i].tv.tv_usec,// info->samp_mt[0][i].slot,// info->samp_mt[0][i].x,// info->samp_mt[0][i].y,// info->samp_mt[0][i].pressure);if(info->samp_mt[0][i].pressure > 0){down_number++;if(s_points[i].type == 0 || s_points[i].type == EVT_TOUCH_UP){s_points[i].type = EVT_TOUCH_DOWN;}else{s_points[i].type = EVT_TOUCH_MOVE;}} else{s_points[i].type = EVT_TOUCH_UP;}s_points[i].finger_id = info->samp_mt[0][i].slot;s_points[i].x = info->samp_mt[0][i].x;s_points[i].y = info->samp_mt[0][i].y;event_number++;main_loop_t *loop = (main_loop_t*)info->dispatch_ctx;touch_event_t touch_event;touch_event_init(&touch_event, s_points[i].type, NULL, 0, info->samp_mt[0][i].slot, info->samp_mt[0][i].x / (double)info->max_x, info->samp_mt[0][i].y / (double)info->max_y, info->samp_mt[0][i].pressure);my_main_loop_post_touch_event(loop, s_points[i].type, &touch_event);// print debug// char *msg = "down";// if(s_points[i].type == EVT_TOUCH_MOVE){//   msg = "move";// }// else if(s_points[i].type == EVT_TOUCH_UP){//   msg = "up";// }// printf("slot %d %s at (%d %d) press %d\r\n", //                             s_points[i].finger_id, //                             msg,//                             s_points[i].x, //                             s_points[i].y, //                             info->samp_mt[0][i].pressure);   }// printf("down number: %d\r\n", down_number);if(event_number == 1  && (info->last_down_number == 0 || info->last_down_number == 1)){struct ts_sample_mt e = info->samp_mt[0][0];req->event.type = EVT_NONE;req->pointer_event.x = e.x;req->pointer_event.y = e.y;// log_debug("%s%d: e.pressure=%d x=%d y=%d ret=%d\n", __func__, __LINE__, e.pressure, e.x, e.y,//           ret);if (e.pressure > 0) {if (req->pointer_event.pressed) {req->event.type = EVT_POINTER_MOVE;} else {req->event.type = EVT_POINTER_DOWN;req->pointer_event.pressed = TRUE;}} else {if (req->pointer_event.pressed) {req->event.type = EVT_POINTER_UP;}req->pointer_event.pressed = FALSE;}info->last_down_number = down_number;return tslib_dispatch(info);}info->last_down_number = down_number;return 0;
}void* tslib_run(void* ctx) {run_info_t info = *(run_info_t*)ctx;if (info.ts == NULL) {log_debug("%s:%d: open tslib failed, filename=%s\n", __func__, __LINE__, info.filename);} else {log_debug("%s:%d: open tslib successful, filename=%s\n", __func__, __LINE__, info.filename);}TKMEM_FREE(ctx);while (tslib_dispatch_one_event(&info) == RET_OK) {};ts_close(info.ts);TKMEM_FREE(info.filename);return NULL;
}static run_info_t* info_dup(run_info_t* info) {run_info_t* new_info = TKMEM_ZALLOC(run_info_t);*new_info = *info;return new_info;
}tk_thread_t* tslib_thread_run(const char* filename, input_dispatch_t dispatch, void* ctx,int32_t max_x, int32_t max_y) {run_info_t info;tk_thread_t* thread = NULL;return_value_if_fail(filename != NULL && dispatch != NULL, NULL);memset(&info, 0x00, sizeof(info));info.max_x = max_x;info.max_y = max_y;info.dispatch_ctx = ctx;info.dispatch = dispatch;info.ts = ts_open(filename, 0);info.filename = tk_strdup(filename);if (info.ts != NULL) {ts_config(info.ts);}
///struct tsdev *ts = info.ts;info.read_samples = 1;info.max_slots = CT_MAX_TOUCH;printf("max_x %d max_y %d TOUCH MAX SLOT=%d\r\n", info.max_x, info.max_y, info.max_slots);info.samp_mt = malloc(info.read_samples * sizeof(struct ts_sample_mt *));if (!info.samp_mt) {printf("create samp_mt failed\r\n");ts_close(ts);return NULL;}for (int i = 0; i < info.read_samples; i++) {info.samp_mt[i] = calloc(info.max_slots, sizeof(struct ts_sample_mt));if (!info.samp_mt[i]) {printf("create samp_mt[%d] failed\r\n", i);for (i--; i >= 0; i--)free(info.samp_mt[i]);free(info.samp_mt);ts_close(ts);return NULL;}}/* 创建不可识别手指类型的多点触控句柄 */touch_points = multi_gesture_touch_points_create(15);memset(s_points, 0x0, sizeof(multi_touch_point_event_t) * CT_MAX_TOUCH);
/thread = tk_thread_create(tslib_run, info_dup(&info));if (thread != NULL) {tk_thread_start(thread);} else {multi_gesture_gesture_touch_points_destroy(touch_points);if (info.samp_mt) {for (int i = 0; i < info.read_samples; i++) {free(info.samp_mt[i]);}free(info.samp_mt);}ts_close(info.ts);TKMEM_FREE(info.filename);}return thread;
}

练习demo地址

https://gitee.com/tracker647/awtk-practice/tree/master/MapImageTouchZoomTest

为了记录做业务学到的东西,我额外写了个demo来演示手指缩放和旋转的操作,采用vgcanvas矢量画布来实现旋转和缩放的效果,原本我想直接从网上下载个地图图片然后用vgcanvas_draw_image绘制,来表示地图的旋转和缩放,但是不知道是不是imx6ull本身图形性能太拉,一在on_paint函数调用vgcanvas_draw_image事件整个应用fps就会下降至1,根本无法正常操作图片,最后只好放弃,改成画一个红色矩形来演示效果:

Video_20250531_110946_12


http://www.hkcw.cn/article/HpFGaTYxEu.shtml

相关文章

电脑重装或者开机出现错误

电脑重装或出现如下错误&#xff0c;遇到的错误信息表明在安装Windows时计算机意外重启或遇到错误&#xff0c;导致安装无法继续&#xff0c;怎么解决&#xff0c;以以下这个电脑举例 按shiftf10出现窗口 输入regedit回车 依次找到以下路径 HKEY_LOCAL_MACHINE/SYSTEM/SETUP…

印军方首次证实有战机被击落 损失数目不详引发关注

印度军方首次证实其在5月份与巴基斯坦的冲突中损失了数量不明的战斗机,同时表示这场为期四天的冲突从未接近核战争爆发点。印度国防参谋长阿尼尔乔汉在新加坡出席香格里拉对话会期间接受采访时说:“重要的并非飞机被击落,而是它们为什么会被击落。”他否认了巴基斯坦方面关于…

为什么当年梅西、内马尔、姆巴佩在巴黎拿不到欧冠,现在球队没有他们反而能夺冠? 青春风暴的胜利

北京时间6月1日凌晨,欧洲冠军联赛决赛落下帷幕。巴黎圣日耳曼队以5比0战胜国际米兰,历史上首次夺得欧冠冠军,并实现了赛季三冠王(法甲、法国杯、欧冠)。多年来,“大巴黎”一直是石油足球和金元足球的代表,坚持“超级巨星路线”,但无论是姆巴佩、梅西还是内马尔都未能带…

【C++】 类和对象(上)

1.类的定义 1.1类的定义格式 • class为定义类的关键字&#xff0c;后跟一个类的名字&#xff0c;{}中为类的主体&#xff0c;注意类定义结束时后⾯分号不能省 略。类体中内容称为类的成员&#xff1a;类中的变量称为类的属性或成员变量;类中的函数称为类的⽅法或 者成员函数。…

Spring之循环依赖源码解析

在学习Spring源码流程解析之前&#xff0c;首先要清楚什么是循环依赖&#xff0c;怎么解决循环依赖再去跟着源码学习一遍&#xff0c;更能加深印象。Mark

贾乃亮晒与甜馨端午节合照 父女笑容神同步

5月31日,贾乃亮在社交媒体上晒出与女儿甜馨的端午节合照,并提问大家猜猜他和甜馨吃的是甜粽还是咸粽。有网友评论说,两人的脸看起来非常相似,就连笑容都很像。甜馨,本名贾云馨,2012年10月23日出生于北京,是演员贾乃亮与李小璐的女儿。2014年4月,她与父亲一起参加了明星…

外交部深夜发声:勿要玩火 坚决反对美方消极言论

6月1日,外交部发言人就美国防长赫格塞思在香格里拉对话会上的涉华消极言论回答了记者提问。有记者问,5月31日,美国防长赫格塞思在香格里拉对话会上发表演讲,大肆渲染中国威胁,并就涉台、南海等问题发表消极言论。对此,中方表示强烈不满和坚决反对,已向美方提出严正交涉。…

零跑汽车5月交付量45067辆 增速超148%

6月1日,据零跑汽车公众号消息,2025年5月,零跑汽车单月交付量45067辆,增速超148%。连续三个月稳居造车新势力领先地位。责任编辑:zx0176

债市全年低点出现在何时 8月和12月规律探析

自2019年降息周期以来,10年国债收益率的全年低点容易出现在8月和12月。这背后的原因可以从基本面、政策面、资金面及机构行为等角度进行分析。从基本面来看,2019年以来,从第二季度开始,GDP增速容易低于全年预期目标,PMI也容易进入下行或低于枯荣线的阶段。而政策发力可能使…

中方回应美防长涉华消极言论 坚决反对美方挑衅挑拨

6月1日,外交部发言人针对美国防长赫格塞思在香格里拉对话会上的涉华消极言论进行了回应。有记者提问称,5月31日,赫格塞思在香格里拉对话会上发表演讲,渲染中国威胁,并就台湾、南海等问题发表负面言论。发言人在回答中指出,赫格塞思无视地区国家追求和平与发展的愿望,兜售…

孟维瞻:马斯克挥一挥衣袖,带走了什么,留下了什么?

【文/观察者网专栏作者 孟维瞻】马斯克离开白宫了。尽管这是一个早就预定好的结局,但在他和特朗普两人关系热火朝天的时候,大家不是没有想过另一种结局。当然,也有很多人在期待,两个人如胶似漆的蜜月期之后是否会反目成仇。如今看来,虽然说不上是反目成仇,至少也是话不投…

南航通报飞机起飞后突然返航 电池冒烟险情妥善处置

5月31日13时许,中国南方航空发布通报称,当天CZ6850杭州飞往深圳的航班上,一名旅客携带的相机电池和充电宝出现冒烟情况。乘务组迅速采取措施,妥善处置,及时排除了安全风险。为确保乘客安全,机组决定立即返航,航班在起飞15分钟后安全降落。航空公司积极做好后续服务保障工…

浙江暴雨将持续至明天上午 需防范次生灾害

不怕七月半鬼,最怕端午水。5月31日,西湖景区一景被拍摄下来。当天下午,浙西北地区开始下雨。到晚上8时,杭州、湖州累计雨量超过了14毫米,单站点最大雨量为52.9毫米,出现在临安区龙塘山。省气象台在16时20分发布暴雨警报:受西南暖湿气流和弱冷空气影响,5月31日夜里至6月…

奇瑞董事长说降价是被绑架的 反内卷呼声高

汽车行业近期出现了对“反内卷”的强烈呼声。在5月31日的2025(第三届)未来汽车先行者大会上,奇瑞汽车董事长尹同跃针对车市价格战表示,“‘价格战’是我最不喜欢的一个词,因为我是被绑架的。”他提到销售团队会告诉他竞争对手已经采取了降价措施,这让他感到非常痛苦和违背…

go|context源码解析

文章目录 Context接口Deadline()Done()Err()Value() canceler接口ctxemptyCtxcancelCtxtimerCtxvalueCtx 基本使用cancelCtxvalueCtx 首先看一下源码对“context”的描述&#xff0c; When a Context is canceled, all Contexts derived from it are also canceled. 当一个Cont…

香港中乐团六月京津巡演 携多位国际艺术家献演

被誉为“民乐翘楚”的香港中乐团受邀于6月13至18日赴北京及天津举行三场“阎惠昌与香港中乐团2025”内地巡演。乐团荣幸获得中华人民共和国香港特别行政区政府驻北京办事处&#xff0c;及巡演赞助商李锦记国际控股有限公司全力支持&#xff0c;将于北京艺术中心的《笙与管风琴的…

[yolov11改进系列]基于yolov11引入高效上采样卷积块EUCB的python源码+训练源码

【EUCB介绍】 论文介绍 题目 EMCAD:Efficient Multi-scale Convolutional Attention Decoding for Medical Image Segmentation 论文地址 https://arxiv.org/pdf/2405.06880 创新点 多尺度卷积解码器&#xff1a;提出了一种高效的多尺度卷积注意力解码器&#xff08;EMCAD&a…

oscp练习PG Monster靶机复现

端口扫描 nmap -A -p- -T4 -Pn 192.168.134.180 PORT STATE SERVICE VERSION 80/tcp open http Apache httpd 2.4.41 ((Win64) OpenSSL/1.1.1c PHP/7.3.10) |_http-server-header: Apache/2.4.41 (Win64) OpenSSL/1.1.1c PHP/7.3.10 | http-methods:…

樊振东莫雷加德成为队友 共迎新挑战

6月1日,萨尔布吕肯俱乐部宣布樊振东加盟德甲联赛。在萨尔布吕肯乒乓球甲级俱乐部的官宣消息中,樊振东表示他非常期待在萨尔布吕肯和德甲的新挑战,体验新的环境,并与球队一起赢得更多胜利。球队经理透露,这一切来得如此令人惊讶且迅速,他们仍然难以完全相信。但这是现实—…

任务中心示例及浏览器强制高效下载实践

1. 效果展示 这里的进度展示&#xff0c;可以通过我们之前讲到的Vue3实现类ChatGPT聊天式流式输出(vue-sse实现) SSE技术实现&#xff0c;比如用户点击全量下载时&#xff0c;后台需要将PDF文件打包为ZIP文件&#xff0c;由于量较大&#xff0c;需要展示进度&#xff0c;用户点…